#!/usr/bin/env ruby # Assumptions: # # - It's okay to ignore mephisto's sections and sites. # - Each mephisto tag should be converted to a Nesta category. require "getoptlong" require "time" require "rubygems" require "active_record" require File.join(File.dirname(__FILE__), *%w[.. lib config]) require File.join(File.dirname(__FILE__), *%w[.. lib models]) class Content < ActiveRecord::Base has_many :taggings, :as => :taggable has_many :tags, :through => :taggings def self.inheritance_column @inheritance_column = "none" end def self.articles conditions = "type = 'Article' and published_at is not NULL" find(:all, :conditions => conditions).map { |c| ArticleLoader.new(c) } end end class Tagging < ActiveRecord::Base belongs_to :content belongs_to :tag end class Tag < ActiveRecord::Base has_many :taggings has_many :contents, :through => :taggings def filename File.join(Nesta::Config.page_path, "#{name}.mdown") end end module ContentWrapper def initialize(content) @content = content end def permalink @content.permalink end private def metadata_string(metadata) metadata.map { |key, value| "#{key}: #{value}" }.sort.join("\n") end end class ArticleLoader include ContentWrapper def filename File.join(Nesta::Config.page_path, "#{permalink}.mdown") end def date @content.published_at end def categories @content.tags.map { |t| t.name }.sort.join(", ") end def summary @content.excerpt.strip.gsub(/\r?\n/, '\n') end def atom_id(domain) published = "#{@content.created_at.strftime('%Y-%m-%d')}" "tag:#{domain},#{published}:#{@content.id}" end def metadata(domain) metadata = { "Date" => date, "Categories" => categories, "Summary" => summary } metadata.merge!("Atom ID" => atom_id(domain)) if domain metadata_string(metadata) end def content ["# #{@content.title}", @content.body.gsub("\r\n", "\n")].join("\n\n") end end class App def usage $stderr.write <<-EOF Usage: #{File.basename $0} [OPTIONS] -u -p OPTIONS (defaults shown in brackets) -a, --adapter Database adapter (mysql) --domain Site's domain name (for preserving tags in feed) --clobber Overwrite existing files -d, --database Database name (mephisto_production) -h, --host Database hostname (localhost) -p, --password Database password -u, --username Database username EOF exit 1 end def parse_command_line parser = GetoptLong.new parser.set_options( ["-a", "--adapter", GetoptLong::REQUIRED_ARGUMENT], ["--domain", GetoptLong::REQUIRED_ARGUMENT], ["--clobber", GetoptLong::NO_ARGUMENT], ["-d", "--database", GetoptLong::REQUIRED_ARGUMENT], ["-h", "--host", GetoptLong::REQUIRED_ARGUMENT], ["-u", "--username", GetoptLong::REQUIRED_ARGUMENT], ["-p", "--password", GetoptLong::REQUIRED_ARGUMENT]) loop do opt, arg = parser.get break if not opt case opt when "-a" @adapter = arg when "--domain" @domain = arg when "--clobber" @clobber = true when "-d" @database = arg when "-h" @host = arg when "-p" @password = arg when "-u" @username = arg end end @adapter ||= "mysql" @clobber.nil? && @clobber = false @host ||= "localhost" @database ||= "mephisto_production" usage if @username.nil? || @password.nil? end def connect_to_database ActiveRecord::Base.establish_connection( :adapter => @adapter, :host => @host, :username => @username, :password => @password, :database => @database ) end def should_import?(item) if File.exist?(item.filename) && (! @clobber) puts "skipping (specify --clobber to overwrite)" false else true end end def import_articles Content.articles.each do |article| puts "Importing article: #{article.permalink}" if should_import?(article) File.open(article.filename, "w") do |file| file.write [article.metadata(@domain), article.content].join("\n\n") end end end end def import_tags Tag.find(:all).each do |tag| puts "Importing tag: #{tag.name}" if should_import?(tag) File.open(tag.filename, "w") do |file| file.write("# #{tag.name.capitalize}\n") end end end end def main parse_command_line connect_to_database import_articles import_tags rescue GetoptLong::Error exit 1 end end app = App.new app.main