class JekyllImport::Importers::MT

Constants

MORE_CONTENT_SEPARATOR
STATUS_DRAFT
STATUS_PUBLISHED
SUPPORTED_ENGINES

Public Class Methods

comment_content(comment, _options = default_options) click to toggle source
# File lib/jekyll-import/importers/mt.rb, line 196
def self.comment_content(comment, _options = default_options)
  comment[:comment_text]
end
comment_date(comment) click to toggle source

Different versions of MT used different column names

# File lib/jekyll-import/importers/mt.rb, line 192
def self.comment_date(comment)
  comment[:comment_modified_on] || comment[:comment_created_on]
end
comment_file_dir_and_base_name(posts_name_by_id, comment, _options = default_options) click to toggle source
# File lib/jekyll-import/importers/mt.rb, line 200
def self.comment_file_dir_and_base_name(posts_name_by_id, comment, _options = default_options)
  post_basename = posts_name_by_id[comment[:comment_entry_id]].sub(%r!\.\w+$!, "")
  comment_id = comment[:comment_id]

  [post_basename, "#{comment_id}.markdown"]
end
comment_metadata(comment, options = default_options) click to toggle source

Extracts metadata for YAML front matter from comment

# File lib/jekyll-import/importers/mt.rb, line 175
def self.comment_metadata(comment, options = default_options)
  metadata = {
    "layout"       => "comment",
    "comment_id"   => comment[:comment_id],
    "post_id"      => comment[:comment_entry_id],
    "author"       => encode(comment[:comment_author], options),
    "email"        => comment[:comment_email],
    "commenter_id" => comment[:comment_commenter_id],
    "date"         => comment_date(comment).strftime("%Y-%m-%d %H:%M:%S %z"),
    "visible"      => comment[:comment_visible] == 1,
    "ip"           => comment[:comment_ip],
    "url"          => comment[:comment_url],
  }
  metadata
end
database_from_opts(options) click to toggle source
# File lib/jekyll-import/importers/mt.rb, line 235
def self.database_from_opts(options)
  engine        = options.fetch("engine", "mysql")
  dbname        = options.fetch("dbname")
  sequel_engine = engine == "mysql" ? "mysql2" : engine

  case engine
  when "sqlite"
    Sequel.sqlite(dbname)
  when "mysql", "postgres"
    db_connect_opts = {
      :host     => options.fetch("host", "127.0.0.1"),
      :user     => options.fetch("user"),
      :password => options.fetch("password", ""),
    }
    db_connect_opts = options["port"] if options["port"]
    Sequel.public_send(
      sequel_engine,
      dbname,
      db_connect_opts
    )
  else
    abort("Unsupported engine: '#{engine}'. Must be one of #{SUPPORTED_ENGINES.join(", ")}")
  end
end
default_options() click to toggle source
# File lib/jekyll-import/importers/mt.rb, line 12
def self.default_options
  {
    "blog_id"       => nil,
    "categories"    => true,
    "dest_encoding" => "utf-8",
    "src_encoding"  => "utf-8",
    "comments"      => false,
  }
end
encode(str, options = default_options) click to toggle source
# File lib/jekyll-import/importers/mt.rb, line 207
def self.encode(str, options = default_options)
  if str.respond_to?(:encoding)
    str.encode(options["dest_encoding"], options["src_encoding"])
  else
    str
  end
end
extra_entry_text_empty?(post) click to toggle source

Extracts text body from post

# File lib/jekyll-import/importers/mt.rb, line 154
def self.extra_entry_text_empty?(post)
  post[:entry_text_more].nil? || post[:entry_text_more].strip.empty?
end
post_content(post, _options = default_options) click to toggle source
# File lib/jekyll-import/importers/mt.rb, line 158
def self.post_content(post, _options = default_options)
  if extra_entry_text_empty?(post)
    post[:entry_text]
  else
    post[:entry_text] + "\n\n#{MORE_CONTENT_SEPARATOR}\n\n" + post[:entry_text_more]
  end
end
post_date(post) click to toggle source

Different versions of MT used different column names

# File lib/jekyll-import/importers/mt.rb, line 149
def self.post_date(post)
  post[:entry_authored_on] || post[:entry_created_on]
end
post_file_name(post, _options = default_options) click to toggle source
# File lib/jekyll-import/importers/mt.rb, line 166
def self.post_file_name(post, _options = default_options)
  date = post_date(post)
  slug = post[:entry_basename]
  file_ext = suffix(post[:entry_convert_breaks])

  "#{date.strftime("%Y-%m-%d")}-#{slug}.#{file_ext}"
end
post_metadata(post, options = default_options) click to toggle source

Extracts metadata for YAML front matter from post

# File lib/jekyll-import/importers/mt.rb, line 133
def self.post_metadata(post, options = default_options)
  metadata = {
    "layout"   => "post",
    "title"    => encode(post[:entry_title], options),
    "date"     => post_date(post).strftime("%Y-%m-%d %H:%M:%S %z"),
    "excerpt"  => encode(post[:entry_excerpt].to_s, options),
    "mt_id"    => post[:entry_id],
    "blog_id"  => post[:entry_blog_id],
    "post_id"  => post[:entry_id], # for link with comments
    "basename" => post[:entry_basename],
  }
  metadata["published"] = false if post[:entry_status] != STATUS_PUBLISHED
  metadata
end
process(options) click to toggle source

Main migrator function. Call this to perform the migration.

dbname

The name of the database

user

The database user name

pass

The database user’s password

host

The address of the MySQL database host. Default: ‘localhost’

options

A hash of configuration options

Supported options are:

blog_id

Specify a single MovableType blog to export by providing blog_id. Default: nil, importer will include posts for all blogs.

categories

If true, save the post’s categories in its YAML front matter. Default: true

src_encoding

Encoding of strings from the database. Default: UTF-8 If your output contains mangled characters, set src_encoding to something appropriate for your database charset.

dest_encoding

Encoding of output strings. Default: UTF-8

comments

If true, output comments in _comments directory, like the one mentioned at github.com/mpalmer/jekyll-static-comments/

# File lib/jekyll-import/importers/mt.rb, line 71
def self.process(options)
  options = default_options.merge(options)

  comments = options.fetch("comments")
  posts_name_by_id = {} if comments

  db = database_from_opts(options)

  post_categories = db[:mt_placement].join(:mt_category, :category_id => :placement_category_id)

  FileUtils.mkdir_p "_posts"

  posts = db[:mt_entry]
  posts = posts.filter(:entry_blog_id => options["blog_id"]) if options["blog_id"]
  posts.each do |post|
    categories = post_categories.filter(
      :placement_entry_id => post[:entry_id]
    ).map { |ea| encode(ea[:category_basename], options) }

    file_name = post_file_name(post, options)

    data = post_metadata(post, options)
    data["categories"] = categories if !categories.empty? && options["categories"]
    yaml_front_matter = data.delete_if { |_, v| v.nil? || v == "" }.to_yaml

    # save post path for comment processing
    posts_name_by_id[data["post_id"]] = file_name if comments

    content = post_content(post, options)

    File.open("_posts/#{file_name}", "w") do |f|
      f.puts yaml_front_matter
      f.puts "---"
      f.puts encode(content, options)
    end
  end

  # process comment output, if enabled
  if comments
    FileUtils.mkdir_p "_comments"

    comments = db[:mt_comment]
    comments.each do |comment|
      next unless posts_name_by_id.key?(comment[:comment_entry_id]) # if the entry exists

      dir_name, base_name = comment_file_dir_and_base_name(posts_name_by_id, comment, options)
      FileUtils.mkdir_p "_comments/#{dir_name}"

      data = comment_metadata(comment, options)
      content = comment_content(comment, options)
      yaml_front_matter = data.delete_if { |_, v| v.nil? || v == "" }.to_yaml

      File.open("_comments/#{dir_name}/#{base_name}", "w") do |f|
        f.puts yaml_front_matter
        f.puts "---"
        f.puts encode(content, options)
      end
    end
  end
end
require_deps() click to toggle source
# File lib/jekyll-import/importers/mt.rb, line 22
def self.require_deps
  JekyllImport.require_with_fallback(%w(
    rubygems
    sequel
    sqlite3
    mysql2
    pg
    fileutils
    safe_yaml
  ))
end
specify_options(c) click to toggle source
# File lib/jekyll-import/importers/mt.rb, line 34
def self.specify_options(c)
  c.option "dbname",        "--dbname DB",              "Database name."
  c.option "user",          "--user USER",              "Database user name."
  c.option "engine",        "--engine ENGINE",          "Database engine ('mysql' or 'postgres'). (default: 'mysql')"
  c.option "password",      "--password PW",            "Database user's password. (default: '')"
  c.option "host",          "--host HOST",              "Database host name. (default: 'localhost')"
  c.option "port",          "--port PORT",              "Custom database port connect to. (default: null)"
  c.option "blog_id",       "--blog_id ID",             "Specify a single Movable Type blog ID to import. (default: null (all blogs))"
  c.option "categories",    "--categories",             "When true, save post's categories in its YAML front matter. (default: true)"
  c.option "src_encoding",  "--src_encoding ENCODING",  "Encoding of strings from database. (default: UTF-8)"
  c.option "dest_encoding", "--dest_encoding ENCODING", "Encoding of output strings. (default: UTF-8)"
  c.option "comments",      "--comments",               "When true, output comments in `_comments` directory. (default: false)"
end
suffix(entry_type) click to toggle source

Ideally, this script would determine the post format (markdown, html, etc) and create files with proper extensions. At this point it just assumes that markdown will be acceptable.

# File lib/jekyll-import/importers/mt.rb, line 218
def self.suffix(entry_type)
  if entry_type.nil? || entry_type.include?("markdown") || entry_type.include?("__default__")
    # The markdown plugin I have saves this as
    # "markdown_with_smarty_pants", so I just look for "markdown".
    "markdown"
  elsif entry_type.include?("textile")
    # This is saved as "textile_2" on my installation of MT 5.1.
    "textile"
  elsif entry_type == "0" || entry_type.include?("richtext")
    # Richtext looks to me like it's saved as HTML, so I include it here.
    "html"
  else
    # Other values might need custom work.
    entry_type
  end
end