jekyll-import 0.1.0.beta3 → 0.1.0.beta4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +6 -14
- data/History.markdown +18 -0
- data/README.markdown +12 -1
- data/jekyll-import.gemspec +31 -25
- data/lib/jekyll-import.rb +50 -1
- data/lib/jekyll-import/importer.rb +11 -0
- data/lib/jekyll-import/importers.rb +10 -0
- data/lib/jekyll-import/importers/csv.rb +50 -0
- data/lib/jekyll-import/importers/drupal6.rb +139 -0
- data/lib/jekyll-import/importers/drupal7.rb +102 -0
- data/lib/jekyll-import/importers/enki.rb +76 -0
- data/lib/jekyll-import/importers/google_reader.rb +68 -0
- data/lib/jekyll-import/importers/joomla.rb +83 -0
- data/lib/jekyll-import/importers/jrnl.rb +127 -0
- data/lib/jekyll-import/importers/marley.rb +72 -0
- data/lib/jekyll-import/importers/mephisto.rb +109 -0
- data/lib/jekyll-import/importers/mt.rb +169 -0
- data/lib/jekyll-import/importers/posterous.rb +139 -0
- data/lib/jekyll-import/importers/rss.rb +71 -0
- data/lib/jekyll-import/importers/s9y.rb +67 -0
- data/lib/jekyll-import/importers/textpattern.rb +76 -0
- data/lib/jekyll-import/importers/tumblr.rb +265 -0
- data/lib/jekyll-import/importers/typo.rb +89 -0
- data/lib/jekyll-import/importers/wordpress.rb +323 -0
- data/lib/jekyll-import/importers/wordpressdotcom.rb +97 -0
- data/lib/jekyll/commands/import.rb +1 -0
- data/test/helper.rb +3 -1
- data/test/test_jrnl_importer.rb +39 -0
- data/test/test_mt_importer.rb +16 -16
- data/test/test_tumblr_importer.rb +61 -0
- data/test/test_wordpress_importer.rb +1 -1
- data/test/test_wordpressdotcom_importer.rb +1 -1
- metadata +53 -32
- data/lib/jekyll/jekyll-import/csv.rb +0 -30
- data/lib/jekyll/jekyll-import/drupal6.rb +0 -112
- data/lib/jekyll/jekyll-import/drupal7.rb +0 -74
- data/lib/jekyll/jekyll-import/enki.rb +0 -49
- data/lib/jekyll/jekyll-import/google_reader.rb +0 -61
- data/lib/jekyll/jekyll-import/joomla.rb +0 -53
- data/lib/jekyll/jekyll-import/marley.rb +0 -52
- data/lib/jekyll/jekyll-import/mephisto.rb +0 -84
- data/lib/jekyll/jekyll-import/mt.rb +0 -142
- data/lib/jekyll/jekyll-import/posterous.rb +0 -122
- data/lib/jekyll/jekyll-import/rss.rb +0 -63
- data/lib/jekyll/jekyll-import/s9y.rb +0 -59
- data/lib/jekyll/jekyll-import/textpattern.rb +0 -58
- data/lib/jekyll/jekyll-import/tumblr.rb +0 -242
- data/lib/jekyll/jekyll-import/typo.rb +0 -69
- data/lib/jekyll/jekyll-import/wordpress.rb +0 -299
- data/lib/jekyll/jekyll-import/wordpressdotcom.rb +0 -84
@@ -0,0 +1,102 @@
|
|
1
|
+
# NOTE: This converter requires Sequel and the MySQL gems.
|
2
|
+
# The MySQL gem can be difficult to install on OS X. Once you have MySQL
|
3
|
+
# installed, running the following commands should work:
|
4
|
+
# $ sudo gem install sequel
|
5
|
+
# $ sudo gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
|
6
|
+
|
7
|
+
module JekyllImport
|
8
|
+
module Importers
|
9
|
+
class Drupal7 < Importer
|
10
|
+
# Reads a MySQL database via Sequel and creates a post file for each story
|
11
|
+
# and blog node.
|
12
|
+
QUERY = "SELECT n.nid, \
|
13
|
+
n.title, \
|
14
|
+
fdb.body_value, \
|
15
|
+
n.created, \
|
16
|
+
n.status \
|
17
|
+
FROM node AS n, \
|
18
|
+
field_data_body AS fdb \
|
19
|
+
WHERE (n.type = 'blog' OR n.type = 'story' OR n.type = 'article') \
|
20
|
+
AND n.nid = fdb.entity_id \
|
21
|
+
AND n.vid = fdb.revision_id"
|
22
|
+
|
23
|
+
def self.validate(options)
|
24
|
+
%w[dbname user].each do |option|
|
25
|
+
if options[option].nil?
|
26
|
+
abort "Missing mandatory option --#{option}."
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.specify_options(c)
|
32
|
+
c.option 'dbname', '--dbname DB', 'Database name'
|
33
|
+
c.option 'user', '--user USER', 'Database user name'
|
34
|
+
c.option 'password', '--password PW', 'Database user\'s password (default: "")'
|
35
|
+
c.option 'host', '--host HOST', 'Database host name (default: "localhost")'
|
36
|
+
c.option 'prefix', '--prefix PREFIX', 'Table prefix name'
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.require_deps
|
40
|
+
JekyllImport.require_with_fallback(%w[
|
41
|
+
rubygems
|
42
|
+
sequel
|
43
|
+
fileutils
|
44
|
+
safe_yaml
|
45
|
+
])
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.process(options)
|
49
|
+
dbname = options.fetch('dbname')
|
50
|
+
user = options.fetch('user')
|
51
|
+
pass = options.fetch('password', "")
|
52
|
+
host = options.fetch('host', "localhost")
|
53
|
+
prefix = options.fetch('prefix', "")
|
54
|
+
|
55
|
+
db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8')
|
56
|
+
|
57
|
+
unless prefix.empty?
|
58
|
+
QUERY[" node "] = " " + prefix + "node "
|
59
|
+
QUERY[" field_data_body "] = " " + prefix + "field_data_body "
|
60
|
+
end
|
61
|
+
|
62
|
+
FileUtils.mkdir_p "_posts"
|
63
|
+
FileUtils.mkdir_p "_drafts"
|
64
|
+
FileUtils.mkdir_p "_layouts"
|
65
|
+
|
66
|
+
db[QUERY].each do |post|
|
67
|
+
# Get required fields and construct Jekyll compatible name
|
68
|
+
node_id = post[:nid]
|
69
|
+
title = post[:title]
|
70
|
+
content = post[:body_value]
|
71
|
+
created = post[:created]
|
72
|
+
time = Time.at(created)
|
73
|
+
is_published = post[:status] == 1
|
74
|
+
dir = is_published ? "_posts" : "_drafts"
|
75
|
+
slug = title.strip.downcase.gsub(/(&|&)/, ' and ').gsub(/[\s\.\/\\]/, '-').gsub(/[^\w-]/, '').gsub(/[-_]{2,}/, '-').gsub(/^[-_]/, '').gsub(/[-_]$/, '')
|
76
|
+
name = time.strftime("%Y-%m-%d-") + slug + '.md'
|
77
|
+
|
78
|
+
# Get the relevant fields as a hash, delete empty fields and convert
|
79
|
+
# to YAML for the header
|
80
|
+
data = {
|
81
|
+
'layout' => 'default',
|
82
|
+
'title' => title.to_s,
|
83
|
+
'created' => created,
|
84
|
+
}.delete_if { |k,v| v.nil? || v == ''}.to_yaml
|
85
|
+
|
86
|
+
# Write out the data and content to file
|
87
|
+
File.open("#{dir}/#{name}", "w") do |f|
|
88
|
+
f.puts data
|
89
|
+
f.puts "---"
|
90
|
+
f.puts content
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
# TODO: Make dirs & files for nodes of type 'page'
|
96
|
+
# Make refresh pages for these as well
|
97
|
+
|
98
|
+
# TODO: Make refresh dirs & files according to entries in url_alias table
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# Adapted by Rodrigo Pinto <rodrigopqn@gmail.com>
|
2
|
+
# Based on typo.rb by Toby DiPasquale
|
3
|
+
|
4
|
+
module JekyllImport
|
5
|
+
module Importers
|
6
|
+
class Enki < Importer
|
7
|
+
SQL = <<-EOS
|
8
|
+
SELECT p.id,
|
9
|
+
p.title,
|
10
|
+
p.slug,
|
11
|
+
p.body,
|
12
|
+
p.published_at as date,
|
13
|
+
p.cached_tag_list as tags
|
14
|
+
FROM posts p
|
15
|
+
EOS
|
16
|
+
|
17
|
+
def self.validate(options)
|
18
|
+
%w[dbname user].each do |option|
|
19
|
+
if options[option].nil?
|
20
|
+
abort "Missing mandatory option --#{option}."
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.specify_options(c)
|
26
|
+
c.option 'dbname', '--dbname', 'Database name'
|
27
|
+
c.option 'user', '--user', 'Database name'
|
28
|
+
c.option 'password', '--password', 'Database name (default: "")'
|
29
|
+
c.option 'host', '--host', 'Database name'
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.require_deps
|
33
|
+
JekyllImport.require_with_fallback(%w[
|
34
|
+
rubygems
|
35
|
+
sequel
|
36
|
+
fileutils
|
37
|
+
pg
|
38
|
+
])
|
39
|
+
end
|
40
|
+
|
41
|
+
# Just working with postgres, but can be easily adapted
|
42
|
+
# to work with both mysql and postgres.
|
43
|
+
def self.process(options)
|
44
|
+
dbname = options.fetch('dbname')
|
45
|
+
user = options.fetch('user')
|
46
|
+
pass = options.fetch('password', "")
|
47
|
+
host = options.fetch('host', "localhost")
|
48
|
+
|
49
|
+
FileUtils.mkdir_p('_posts')
|
50
|
+
db = Sequel.postgres(:database => dbname,
|
51
|
+
:user => user,
|
52
|
+
:password => pass,
|
53
|
+
:host => host,
|
54
|
+
:encoding => 'utf8')
|
55
|
+
|
56
|
+
db[SQL].each do |post|
|
57
|
+
name = [ sprintf("%.04d", post[:date].year),
|
58
|
+
sprintf("%.02d", post[:date].month),
|
59
|
+
sprintf("%.02d", post[:date].day),
|
60
|
+
post[:slug].strip ].join('-')
|
61
|
+
name += '.textile'
|
62
|
+
|
63
|
+
File.open("_posts/#{name}", 'w') do |f|
|
64
|
+
f.puts({ 'layout' => 'post',
|
65
|
+
'title' => post[:title].to_s,
|
66
|
+
'enki_id' => post[:id],
|
67
|
+
'categories' => post[:tags]
|
68
|
+
}.delete_if { |k, v| v.nil? || v == '' }.to_yaml)
|
69
|
+
f.puts '---'
|
70
|
+
f.puts post[:body].delete("\r")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# Usage:
|
2
|
+
# (Local file)
|
3
|
+
# ruby -r 'jekyll/jekyll-import/rss' -e "JekyllImport::GoogleReader.process(:source => './somefile/on/your/computer.xml')"
|
4
|
+
|
5
|
+
module JekyllImport
|
6
|
+
module Importers
|
7
|
+
class GoogleReader < Importer
|
8
|
+
def self.validate(options)
|
9
|
+
if options['source'].nil?
|
10
|
+
abort "Missing mandatory option --source."
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.specify_options(c)
|
15
|
+
c.option 'source', '--source', 'Source XML file of Google Reader export'
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.require_deps
|
19
|
+
JekyllImport.require_with_fallback(%w[
|
20
|
+
rubygems
|
21
|
+
rss
|
22
|
+
fileutils
|
23
|
+
safe_yaml
|
24
|
+
open-url
|
25
|
+
rexml/document
|
26
|
+
date
|
27
|
+
])
|
28
|
+
end
|
29
|
+
|
30
|
+
# Process the import.
|
31
|
+
#
|
32
|
+
# source - a URL or a local file String.
|
33
|
+
#
|
34
|
+
# Returns nothing.
|
35
|
+
def self.process(options)
|
36
|
+
source = options.fetch('source')
|
37
|
+
|
38
|
+
open(source) do |content|
|
39
|
+
feed = RSS::Parser.parse(content)
|
40
|
+
|
41
|
+
raise "There doesn't appear to be any RSS items at the source (#{source}) provided." unless feed
|
42
|
+
|
43
|
+
feed.items.each do |item|
|
44
|
+
title = item.title.content.to_s
|
45
|
+
formatted_date = Date.parse(item.published.to_s)
|
46
|
+
post_name = title.split(%r{ |!|/|:|&|-|$|,}).map do |i|
|
47
|
+
i.downcase if i != ''
|
48
|
+
end.compact.join('-')
|
49
|
+
name = "#{formatted_date}-#{post_name}"
|
50
|
+
|
51
|
+
header = {
|
52
|
+
'layout' => 'post',
|
53
|
+
'title' => title
|
54
|
+
}
|
55
|
+
|
56
|
+
FileUtils.mkdir_p("_posts")
|
57
|
+
|
58
|
+
File.open("_posts/#{name}.html", "w") do |f|
|
59
|
+
f.puts header.to_yaml
|
60
|
+
f.puts "---\n\n"
|
61
|
+
f.puts item.content.content.to_s
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# NOTE: This migrator is made for Joomla 1.5 databases.
|
2
|
+
# NOTE: This converter requires Sequel and the MySQL gems.
|
3
|
+
# The MySQL gem can be difficult to install on OS X. Once you have MySQL
|
4
|
+
# installed, running the following commands should work:
|
5
|
+
# $ sudo gem install sequel
|
6
|
+
# $ sudo gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
|
7
|
+
|
8
|
+
module JekyllImport
|
9
|
+
module Importers
|
10
|
+
class Joomla < Importer
|
11
|
+
def self.validate(options)
|
12
|
+
%w[dbname user].each do |option|
|
13
|
+
if options[option].nil?
|
14
|
+
abort "Missing mandatory option --#{option}."
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.specify_options(c)
|
20
|
+
c.option 'dbname', '--dbname', 'Database name'
|
21
|
+
c.option 'user', '--user', 'Database user name'
|
22
|
+
c.option 'password', '--password', "Database user's password (default: '')"
|
23
|
+
c.option 'host', '--host', 'Database host name'
|
24
|
+
c.option 'section', '--section', 'Table prefix name'
|
25
|
+
c.option 'prefix', '--prefix', 'Table prefix name'
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.require_deps
|
29
|
+
JekyllImport.require_with_fallback(%w[
|
30
|
+
rubygems
|
31
|
+
sequel
|
32
|
+
fileutils
|
33
|
+
safe_yaml
|
34
|
+
])
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.process(options)
|
38
|
+
dbname = options.fetch('dbname')
|
39
|
+
user = options.fetch('user')
|
40
|
+
pass = options.fetch('password', '')
|
41
|
+
host = options.fetch('host', "localhost")
|
42
|
+
section = options.fetch('section', '1')
|
43
|
+
table_prefix = options.fetch('prefix', "jos_")
|
44
|
+
|
45
|
+
db = Sequel.mysql(dbname, :user => user, :password => pass, :host => host, :encoding => 'utf8')
|
46
|
+
|
47
|
+
FileUtils.mkdir_p("_posts")
|
48
|
+
|
49
|
+
# Reads a MySQL database via Sequel and creates a post file for each
|
50
|
+
# post in wp_posts that has post_status = 'publish'. This restriction is
|
51
|
+
# made because 'draft' posts are not guaranteed to have valid dates.
|
52
|
+
query = "SELECT `title`, `alias`, CONCAT(`introtext`,`fulltext`) as content, `created`, `id` FROM #{table_prefix}content WHERE state = '0' OR state = '1' AND sectionid = '#{section}'"
|
53
|
+
|
54
|
+
db[query].each do |post|
|
55
|
+
# Get required fields and construct Jekyll compatible name.
|
56
|
+
title = post[:title]
|
57
|
+
slug = post[:alias]
|
58
|
+
date = post[:created]
|
59
|
+
content = post[:content]
|
60
|
+
name = "%02d-%02d-%02d-%s.markdown" % [date.year, date.month, date.day,
|
61
|
+
slug]
|
62
|
+
|
63
|
+
# Get the relevant fields as a hash, delete empty fields and convert
|
64
|
+
# to YAML for the header.
|
65
|
+
data = {
|
66
|
+
'layout' => 'post',
|
67
|
+
'title' => title.to_s,
|
68
|
+
'joomla_id' => post[:id],
|
69
|
+
'joomla_url' => post[:alias],
|
70
|
+
'date' => date
|
71
|
+
}.delete_if { |k,v| v.nil? || v == '' }.to_yaml
|
72
|
+
|
73
|
+
# Write out the data and content to file
|
74
|
+
File.open("_posts/#{name}", "w") do |f|
|
75
|
+
f.puts data
|
76
|
+
f.puts "---"
|
77
|
+
f.puts content
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# Author: Aniket Pant <me@aniketpant.com>
|
2
|
+
|
3
|
+
module JekyllImport
|
4
|
+
module Importers
|
5
|
+
class Jrnl < Importer
|
6
|
+
|
7
|
+
def self.require_deps
|
8
|
+
JekyllImport.require_with_fallback(%w[
|
9
|
+
time
|
10
|
+
rubygems
|
11
|
+
safe_yaml
|
12
|
+
])
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.specify_options(c)
|
16
|
+
c.option 'file', '--file FILENAME', 'Journal file (default: "~/journal.txt")'
|
17
|
+
c.option 'time_format', '--time_format FORMAT', 'Time format of your journal (default: "%Y-%m-%d %H:%M")'
|
18
|
+
c.option 'extension', '--extension EXT', 'Output extension (default: "md")'
|
19
|
+
c.option 'layout', '--layout NAME', 'Output post layout (default: "post")'
|
20
|
+
end
|
21
|
+
|
22
|
+
# Reads a jrnl file and creates a new post for each entry
|
23
|
+
# The following overrides are available:
|
24
|
+
# :file path to input file
|
25
|
+
# :time_format the format used by the jrnl configuration
|
26
|
+
# :extension the extension format of the output files
|
27
|
+
# :layout explicitly set the layout of the output
|
28
|
+
def self.process(options)
|
29
|
+
file = options.fetch('file', "~/journal.txt")
|
30
|
+
time_format = options.fetch('time_format', "%Y-%m-%d %H:%M")
|
31
|
+
extension = options.fetch('extension', "md")
|
32
|
+
layout = options.fetch('layout', "post")
|
33
|
+
|
34
|
+
date_length = Time.now.strftime(time_format).length
|
35
|
+
|
36
|
+
# convert relative to absolute if needed
|
37
|
+
file = File.expand_path(file)
|
38
|
+
|
39
|
+
abort "The jrnl file was not found. Please make sure '#{file}' exists. You can specify a different file using the --file switch." unless File.file?(file)
|
40
|
+
|
41
|
+
input = File.read(file)
|
42
|
+
entries = input.split("\n\n");
|
43
|
+
|
44
|
+
entries.each do |entry|
|
45
|
+
# split dateline and body
|
46
|
+
# content[0] has the date and title
|
47
|
+
# content[1] has the post body
|
48
|
+
content = entry.split("\n")
|
49
|
+
|
50
|
+
body = get_post_content(content)
|
51
|
+
date = get_date(content[0], date_length)
|
52
|
+
title = get_title(content[0], date_length)
|
53
|
+
slug = create_slug(title)
|
54
|
+
filename = create_filename(date, slug, extension)
|
55
|
+
meta = create_meta(layout, title, date) # prepare YAML meta data
|
56
|
+
|
57
|
+
write_file(filename, meta, body) # write to file
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# strip body from jrnl entry
|
62
|
+
def self.get_post_content(content)
|
63
|
+
return content[1]
|
64
|
+
end
|
65
|
+
|
66
|
+
# strip timestamp from the dateline
|
67
|
+
def self.get_date(content, offset)
|
68
|
+
return content[0, offset]
|
69
|
+
end
|
70
|
+
|
71
|
+
# strip title from the dateline
|
72
|
+
def self.get_title(content, offset)
|
73
|
+
return content[offset + 1, content.length]
|
74
|
+
end
|
75
|
+
|
76
|
+
# generate slug
|
77
|
+
def self.create_slug(title)
|
78
|
+
return title.downcase.strip.gsub(' ', '-').gsub(/[^\w-]/, '')
|
79
|
+
end
|
80
|
+
|
81
|
+
# generate filename
|
82
|
+
def self.create_filename(date, slug, extension)
|
83
|
+
return "#{Time.parse(date).strftime("%Y-%m-%d")}-#{slug}.#{extension}"
|
84
|
+
end
|
85
|
+
|
86
|
+
# Prepare YAML meta data
|
87
|
+
#
|
88
|
+
# layout - name of the layout
|
89
|
+
# title - title of the entry
|
90
|
+
# date - date of entry creation
|
91
|
+
#
|
92
|
+
# Examples
|
93
|
+
#
|
94
|
+
# create_meta("post", "Entry 1", "2013-01-01 13:00")
|
95
|
+
# # => "---\nlayout: post\ntitle: Entry 1\ndate: 2013-01-01 13:00\n"
|
96
|
+
#
|
97
|
+
# Returns array converted to YAML
|
98
|
+
def self.create_meta(layout, title, date)
|
99
|
+
data = {
|
100
|
+
'layout' => layout,
|
101
|
+
'title' => title,
|
102
|
+
'date' => Time.parse(date).strftime("%Y-%m-%d %H:%M %z")
|
103
|
+
}.to_yaml
|
104
|
+
return data;
|
105
|
+
end
|
106
|
+
|
107
|
+
# Writes given data to file
|
108
|
+
#
|
109
|
+
# filename - name of the output file
|
110
|
+
# meta - YAML header data
|
111
|
+
# body - jrnl entry content
|
112
|
+
#
|
113
|
+
# Examples
|
114
|
+
#
|
115
|
+
# write_file("2013-01-01-entry-1.md", "---\nlayout: post\ntitle: Entry 1\ndate: 2013-01-01 13:00\n", "This is the first entry for my new journal")
|
116
|
+
#
|
117
|
+
# Writes file to _posts/filename
|
118
|
+
def self.write_file(filename, meta, body)
|
119
|
+
File.open("_posts/#{filename}", "w") do |f|
|
120
|
+
f.puts meta
|
121
|
+
f.puts "---\n\n"
|
122
|
+
f.puts body
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|