caramelize 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +19 -24
- data/bin/caramelize +48 -2
- data/caramelize.gemspec +2 -1
- data/lib/caramelize.rb +12 -0
- data/lib/caramelize/caramel.rb +33 -29
- data/lib/caramelize/content_transferer.rb +78 -111
- data/lib/caramelize/filter_processor.rb +31 -0
- data/lib/caramelize/input_wiki/redmine_wiki.rb +97 -0
- data/lib/caramelize/{wiki → input_wiki}/trac_converter.rb +0 -0
- data/lib/caramelize/input_wiki/wiki.rb +61 -0
- data/lib/caramelize/input_wiki/wikkawiki.rb +57 -0
- data/lib/caramelize/output_wiki/gollum.rb +73 -0
- data/lib/caramelize/page.rb +10 -4
- data/lib/caramelize/services/page_builder.rb +20 -0
- data/lib/caramelize/version.rb +1 -1
- data/spec/lib/caramelize/content_transferer_spec.rb +9 -0
- data/spec/lib/caramelize/filter_processor_spec.rb +32 -0
- data/spec/lib/caramelize/filters/wikka_to_markdown_spec.rb +25 -13
- data/spec/lib/caramelize/{wiki → input_wiki}/wiki_spec.rb +30 -4
- data/spec/lib/caramelize/output_wiki/gollum_spec.rb +113 -0
- data/spec/lib/caramelize/page_spec.rb +49 -0
- data/spec/lib/caramelize/services/page_builder.rb +29 -0
- data/spec/spec_helper.rb +1 -1
- metadata +38 -17
- data/lib/caramelize/cli.rb +0 -89
- data/lib/caramelize/cli/create_command.rb +0 -36
- data/lib/caramelize/cli/run_command.rb +0 -33
- data/lib/caramelize/gollum_output.rb +0 -79
- data/lib/caramelize/wiki/redmine_wiki.rb +0 -88
- data/lib/caramelize/wiki/wiki.rb +0 -63
- data/lib/caramelize/wiki/wikkawiki.rb +0 -48
- data/spec/lib/caramelize/gollum_output_spec.rb +0 -64
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'gollum-lib'
|
2
|
+
require 'grit'
|
3
|
+
require 'ruby-progressbar'
|
4
|
+
|
5
|
+
module Caramelize
|
6
|
+
class FilterProcessor
|
7
|
+
attr_reader :filters, :input_wiki
|
8
|
+
|
9
|
+
def initialize(input_wiki)
|
10
|
+
@filters = []
|
11
|
+
@input_wiki = input_wiki
|
12
|
+
|
13
|
+
initialize_wiki_filters
|
14
|
+
end
|
15
|
+
|
16
|
+
def run(body)
|
17
|
+
body_new = body
|
18
|
+
filters.each do |filter|
|
19
|
+
body_new = filter.run(body_new)
|
20
|
+
end
|
21
|
+
body_new
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def initialize_wiki_filters
|
27
|
+
filters << input_wiki.filters
|
28
|
+
filters.flatten!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'caramelize/input_wiki/wiki'
|
2
|
+
require 'caramelize/filters/swap_wiki_links'
|
3
|
+
require 'caramelize/filters/remove_table_tab_line_endings'
|
4
|
+
|
5
|
+
module Caramelize
|
6
|
+
module InputWiki
|
7
|
+
class RedmineWiki < Wiki
|
8
|
+
include DatabaseConnector
|
9
|
+
|
10
|
+
def initialize options={}
|
11
|
+
super(options)
|
12
|
+
@options[:markup] = :textile
|
13
|
+
@options[:filters] << Caramelize::SwapWikiLinks.new
|
14
|
+
@options[:filters] << Caramelize::RemoveTableTabLineEndings.new
|
15
|
+
@options[:create_namespace_overview] = true
|
16
|
+
end
|
17
|
+
|
18
|
+
# after calling this action, I expect the titles and revisions to be filled
|
19
|
+
def read_pages
|
20
|
+
# get all projects
|
21
|
+
results_projects = database.query("SELECT id, identifier, name FROM projects;")
|
22
|
+
results_projects.each do |row_project|
|
23
|
+
#collect all namespaces
|
24
|
+
namespaces << OpenStruct.new(identifier: row_project["identifier"], name: row_project["name"])
|
25
|
+
end
|
26
|
+
|
27
|
+
# get all wikis
|
28
|
+
results_wikis = database.query("SELECT id, project_id FROM wikis;")
|
29
|
+
|
30
|
+
# get all lemmas
|
31
|
+
results_pages = database.query("SELECT id, title, wiki_id FROM wiki_pages;")
|
32
|
+
results_pages.each do |row_page|
|
33
|
+
results_contents = database.query("SELECT * FROM wiki_content_versions WHERE page_id='#{row_page["id"]}' ORDER BY updated_on;")
|
34
|
+
|
35
|
+
# get wiki for page
|
36
|
+
wiki_row = nil
|
37
|
+
project_row = nil
|
38
|
+
results_wikis.each do |wiki|
|
39
|
+
wiki_row = wiki if wiki["id"] == row_page["wiki_id"]
|
40
|
+
end
|
41
|
+
|
42
|
+
if wiki_row
|
43
|
+
# get project from wiki-id
|
44
|
+
results_projects.each do |project|
|
45
|
+
project_row = project if project["id"] == wiki_row["project_id"]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
project_identifier = project_row ? project_row["identifier"] + '/' : ""
|
50
|
+
|
51
|
+
title = project_identifier + row_page["title"]
|
52
|
+
titles << title
|
53
|
+
|
54
|
+
@latest_revisions = {}
|
55
|
+
results_contents.each do |row_content|
|
56
|
+
page = Page.new(build_properties(title, row_content))
|
57
|
+
revisions << page
|
58
|
+
@latest_revisions[title] = page
|
59
|
+
end
|
60
|
+
end
|
61
|
+
titles.uniq!
|
62
|
+
@latest_revisions.each { |rev| rev[1].set_latest }
|
63
|
+
revisions.sort! { |a,b| a.time <=> b.time }
|
64
|
+
|
65
|
+
# TODO find latest revision for each limit
|
66
|
+
|
67
|
+
revisions
|
68
|
+
end
|
69
|
+
|
70
|
+
def read_authors
|
71
|
+
results = database.query("SELECT id, login, mail FROM users;")
|
72
|
+
results.each do |row|
|
73
|
+
authors[row["id"]] = OpenStruct.new(id: row["id"],
|
74
|
+
name: row["login"],
|
75
|
+
email: row["mail"])
|
76
|
+
end
|
77
|
+
authors
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def build_properties(title, row_content)
|
83
|
+
author = authors[row_content["author_id"]] ? authors[row_content["author_id"]] : nil
|
84
|
+
{ id: row_content["id"],
|
85
|
+
title: title,
|
86
|
+
body: row_content["data"],
|
87
|
+
markup: :textile,
|
88
|
+
latest: false,
|
89
|
+
time: row_content["updated_on"],
|
90
|
+
message: row_content["comments"],
|
91
|
+
author: author,
|
92
|
+
author_name: author.name
|
93
|
+
}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
File without changes
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Caramelize
|
2
|
+
module InputWiki
|
3
|
+
class Wiki
|
4
|
+
include DatabaseConnector
|
5
|
+
|
6
|
+
attr_accessor :revisions, :wiki_title, :titles, :description, :namespaces, :options
|
7
|
+
|
8
|
+
def initialize(options={})
|
9
|
+
@options = options
|
10
|
+
@options[:filters] = []
|
11
|
+
@namespaces = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def revisions_by_title(title)
|
15
|
+
# new array only containing pages by this name sorted by time asc
|
16
|
+
# this does not support renamed pages
|
17
|
+
return revisions
|
18
|
+
.select { |revision| revision.title == title }
|
19
|
+
.sort { |x,y| x.time <=> y.time }
|
20
|
+
end
|
21
|
+
|
22
|
+
# return an empty array in case this action was not overridden
|
23
|
+
def read_authors
|
24
|
+
[]
|
25
|
+
end
|
26
|
+
|
27
|
+
def namespaces
|
28
|
+
@namespaces ||= {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def authors
|
32
|
+
@authors ||= {}
|
33
|
+
end
|
34
|
+
|
35
|
+
def revisions
|
36
|
+
@revisions ||= []
|
37
|
+
end
|
38
|
+
|
39
|
+
def titles
|
40
|
+
@titles ||= []
|
41
|
+
end
|
42
|
+
|
43
|
+
def convert_markup?(to_markup)
|
44
|
+
markup != to_markup
|
45
|
+
end
|
46
|
+
|
47
|
+
def filters
|
48
|
+
@options[:filters]
|
49
|
+
end
|
50
|
+
|
51
|
+
def latest_revisions
|
52
|
+
titles.map { |title| revisions_by_title(title).last }.compact
|
53
|
+
end
|
54
|
+
|
55
|
+
def markup
|
56
|
+
@options[:markup]
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'caramelize/input_wiki/wiki'
|
2
|
+
require 'caramelize/database_connector'
|
3
|
+
require 'caramelize/filters/wikka_to_markdown'
|
4
|
+
|
5
|
+
module Caramelize
|
6
|
+
module InputWiki
|
7
|
+
class WikkaWiki < Wiki
|
8
|
+
include DatabaseConnector
|
9
|
+
|
10
|
+
def initialize options={}
|
11
|
+
super(options)
|
12
|
+
@options[:markup] = :wikka
|
13
|
+
@options[:filters] << Caramelize::Wikka2Markdown.new
|
14
|
+
end
|
15
|
+
|
16
|
+
# after calling this action, titles and @revisions are expected to be filled
|
17
|
+
def read_pages
|
18
|
+
sql = "SELECT id, tag, body, time, latest, user, note FROM wikka_pages ORDER BY time;"
|
19
|
+
results = database.query(sql)
|
20
|
+
results.each do |row|
|
21
|
+
titles << row["tag"]
|
22
|
+
page = Page.new(build_properties(row))
|
23
|
+
revisions << page
|
24
|
+
end
|
25
|
+
titles.uniq!
|
26
|
+
#revisions.sort! { |a,b| a.time <=> b.time }
|
27
|
+
|
28
|
+
revisions
|
29
|
+
end
|
30
|
+
|
31
|
+
def read_authors
|
32
|
+
sql = "SELECT name, email FROM wikka_users;"
|
33
|
+
results = database.query(sql)
|
34
|
+
results.each do |row|
|
35
|
+
authors[row["name"]] = OpenStruct.new(name: row["name"],
|
36
|
+
email: row["email"] )
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def build_properties(row)
|
43
|
+
author = authors[row["user"]]
|
44
|
+
{ id: row["id"],
|
45
|
+
title: row["tag"],
|
46
|
+
body: row["body"],
|
47
|
+
markup: :wikka,
|
48
|
+
latest: row["latest"] == "Y",
|
49
|
+
time: row["time"],
|
50
|
+
message: row["note"],
|
51
|
+
author: author,
|
52
|
+
author_name: row["user"]
|
53
|
+
}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'caramelize/ext'
|
2
|
+
module Caramelize
|
3
|
+
module OutputWiki
|
4
|
+
class Gollum
|
5
|
+
|
6
|
+
attr_reader :wiki_path
|
7
|
+
|
8
|
+
SUPPORTED_TARGET_MARKUP =
|
9
|
+
%i[markdown textile rdoc creole media_wiki org pod re_structured_text ascii_doc].freeze
|
10
|
+
|
11
|
+
# Initialize a new gollum-wiki-repository at the given path.
|
12
|
+
def initialize(new_wiki_path)
|
13
|
+
# TODO use sanitized name as wiki-repository-title
|
14
|
+
@wiki_path = new_wiki_path
|
15
|
+
initialize_repository
|
16
|
+
end
|
17
|
+
|
18
|
+
# Commit the given page into the gollum-wiki-repository.
|
19
|
+
# Make sure the target markup is correct before calling this method.
|
20
|
+
def commit_revision(page, markup)
|
21
|
+
gollum_page = gollum.page(page.title)
|
22
|
+
|
23
|
+
if gollum_page
|
24
|
+
gollum.update_page(gollum_page, gollum_page.name, gollum_page.format, page.body, build_commit(page))
|
25
|
+
else
|
26
|
+
gollum.write_page(page.title, markup, page.body, build_commit(page))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Commit all revisions of the given history into this gollum-wiki-repository.
|
31
|
+
def commit_history(revisions, options = {}, &block)
|
32
|
+
revisions.each_with_index do |page, index|
|
33
|
+
# call debug output from outside
|
34
|
+
block.call(page, index) if block_given?
|
35
|
+
commit_revision(page, options.fetch(:markup, :markdown))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def commit_namespace_overview(namespaces)
|
40
|
+
commit_revision(build_namespace_overview(namespaces), :markdown)
|
41
|
+
end
|
42
|
+
|
43
|
+
def supported_markup
|
44
|
+
SUPPORTED_TARGET_MARKUP
|
45
|
+
end
|
46
|
+
|
47
|
+
def build_commit(page)
|
48
|
+
{
|
49
|
+
message: page.commit_message,
|
50
|
+
name: page.author_name,
|
51
|
+
email: page.author_email,
|
52
|
+
authored_date: page.time,
|
53
|
+
committed_date: page.time
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def build_namespace_overview(namespaces)
|
60
|
+
::Caramelize::Services::PageBuilder.build_namespace_overview(namespaces)
|
61
|
+
end
|
62
|
+
|
63
|
+
def gollum
|
64
|
+
@gollum ||= ::Gollum::Wiki.new(wiki_path)
|
65
|
+
end
|
66
|
+
|
67
|
+
def initialize_repository
|
68
|
+
return if File.exists?(wiki_path)
|
69
|
+
Grit::Repo.init(wiki_path)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/caramelize/page.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
module Caramelize
|
2
2
|
class Page
|
3
3
|
|
4
|
-
attr_accessor :title, :body, :id, :markup, :latest, :time, :message,
|
4
|
+
attr_accessor :title, :body, :id, :markup, :latest, :time, :message,
|
5
|
+
:author, :author_name
|
5
6
|
|
6
|
-
def initialize
|
7
|
+
def initialize(page={})
|
7
8
|
@id = page[:id]
|
8
9
|
@title = page[:title] || ""
|
9
10
|
@body = page[:body] || ""
|
@@ -12,7 +13,7 @@ module Caramelize
|
|
12
13
|
@time = page[:time] || Time.now
|
13
14
|
@message = page[:message] || ""
|
14
15
|
@author = page[:author]
|
15
|
-
@author_name =
|
16
|
+
@author_name = page[:author_name]
|
16
17
|
end
|
17
18
|
|
18
19
|
def author_email
|
@@ -39,5 +40,10 @@ module Caramelize
|
|
39
40
|
def to_s
|
40
41
|
@title
|
41
42
|
end
|
43
|
+
|
44
|
+
def commit_message
|
45
|
+
return "Edit in page #{title}" if message.empty?
|
46
|
+
message
|
47
|
+
end
|
42
48
|
end
|
43
|
-
end
|
49
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Caramelize
|
2
|
+
module Services
|
3
|
+
class PageBuilder
|
4
|
+
def self.build_namespace_overview(namespaces)
|
5
|
+
body = "## Overview of namespaces\n\n"
|
6
|
+
|
7
|
+
namespaces.each do |namespace|
|
8
|
+
# TODO change wiki as configurable default home
|
9
|
+
# TODO support other markup syntaxes
|
10
|
+
body << "* [[#{namespace[:name]}|#{namespace[:identifier]}/Wiki]] \n"
|
11
|
+
end
|
12
|
+
|
13
|
+
Page.new(title: "Home",
|
14
|
+
body: body,
|
15
|
+
message: 'Create Namespace Overview',
|
16
|
+
latest: true)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/caramelize/version.rb
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Caramelize::FilterProcessor do
|
4
|
+
let(:filters) { [] }
|
5
|
+
let(:input_wiki) { double(filters: filters) }
|
6
|
+
let(:body) { 'body' }
|
7
|
+
subject(:processor) { described_class.new(input_wiki) }
|
8
|
+
|
9
|
+
class ReverseFilter
|
10
|
+
def run(body)
|
11
|
+
body.reverse
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#run' do
|
16
|
+
context 'without any filters' do
|
17
|
+
it 'returns same revision body' do
|
18
|
+
expect(processor.run(body)).to eql body
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'with reverse filter' do
|
23
|
+
let(:filters) do
|
24
|
+
[ReverseFilter.new]
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'returns reversed body' do
|
28
|
+
expect(processor.run(body)).to eql body.reverse
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -5,81 +5,93 @@ describe Caramelize::Wikka2Markdown do
|
|
5
5
|
describe :run do
|
6
6
|
let(:filter) { Caramelize::Wikka2Markdown.new }
|
7
7
|
context 'headline h1' do
|
8
|
-
it '
|
8
|
+
it 'converts to markdown' do
|
9
9
|
body = '======Headline======'
|
10
10
|
expect(filter.run(body)).to eq '# Headline'
|
11
11
|
end
|
12
12
|
end
|
13
|
+
|
13
14
|
context 'headline h2' do
|
14
|
-
it '
|
15
|
+
it 'converts to markdown' do
|
15
16
|
body = '=====Headline====='
|
16
17
|
expect(filter.run(body)).to eq '## Headline'
|
17
18
|
end
|
18
19
|
end
|
20
|
+
|
19
21
|
context 'headline h3' do
|
20
|
-
it '
|
22
|
+
it 'converts to markdown' do
|
21
23
|
body = '====Headline===='
|
22
24
|
expect(filter.run(body)).to eq '### Headline'
|
23
25
|
end
|
24
26
|
end
|
27
|
+
|
25
28
|
context 'headline h4' do
|
26
|
-
it '
|
29
|
+
it 'converts to markdown' do
|
27
30
|
body = '===Headline==='
|
28
31
|
expect(filter.run(body)).to eq '#### Headline'
|
29
32
|
end
|
30
33
|
end
|
34
|
+
|
31
35
|
context 'headline h1' do
|
32
|
-
it '
|
36
|
+
it 'converts to markdown' do
|
33
37
|
body = '======Headline======'
|
34
38
|
expect(filter.run(body)).to eq '# Headline'
|
35
39
|
end
|
36
40
|
end
|
41
|
+
|
37
42
|
context 'bold' do
|
38
|
-
it '
|
43
|
+
it 'converts to markdown' do
|
39
44
|
body = '**Text is bold**'
|
40
45
|
expect(filter.run(body)).to eq '**Text is bold**'
|
41
46
|
end
|
42
47
|
end
|
48
|
+
|
43
49
|
context 'italic' do
|
44
|
-
it '
|
50
|
+
it 'converts to markdown' do
|
45
51
|
body = '//Text is italic//'
|
46
52
|
expect(filter.run(body)).to eq '_Text is italic_'
|
47
53
|
end
|
48
54
|
end
|
55
|
+
|
49
56
|
context 'underline' do
|
50
|
-
it '
|
57
|
+
it 'converts to markdown' do
|
51
58
|
body = '__Text is underlined__'
|
52
59
|
expect(filter.run(body)).to eq '<u>Text is underlined</u>'
|
53
60
|
end
|
54
61
|
end
|
62
|
+
|
55
63
|
context 'line break' do
|
56
|
-
it '
|
64
|
+
it 'converts to markdown' do
|
57
65
|
body = 'Text is---\nbroken to two lines.'
|
58
66
|
expect(filter.run(body)).to eq 'Text is \nbroken to two lines.'
|
59
67
|
end
|
60
68
|
end
|
69
|
+
|
61
70
|
context 'unordered list entry' do
|
62
71
|
context 'tab based' do
|
63
|
-
it '
|
72
|
+
it 'converts to markdown' do
|
64
73
|
body = "\t-unordered list entry"
|
65
74
|
expect(filter.run(body)).to eq '*unordered list entry'
|
66
75
|
end
|
67
76
|
end
|
77
|
+
|
68
78
|
context 'also tab based' do
|
69
|
-
it '
|
79
|
+
it 'converts to markdown' do
|
70
80
|
body = "~-unordered list entry"
|
71
81
|
expect(filter.run(body)).to eq '*unordered list entry'
|
72
82
|
end
|
73
83
|
end
|
84
|
+
|
74
85
|
context 'space based' do
|
75
|
-
it '
|
86
|
+
it 'converts to markdown' do
|
76
87
|
body = " -unordered list entry"
|
77
88
|
expect(filter.run(body)).to eq '*unordered list entry'
|
78
89
|
end
|
79
90
|
end
|
80
91
|
end
|
92
|
+
|
81
93
|
context 'hyperlink' do
|
82
|
-
it '
|
94
|
+
it 'converts to markdown' do
|
83
95
|
body = '[[Title http://target]]'
|
84
96
|
expect(filter.run(body)).to eq '[[http://target|Title]]'
|
85
97
|
end
|