caramelize 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|