1
|
# redMine - project management software
|
2
|
# Copyright (C) 2008 Karl Heinz Marbaise
|
3
|
#
|
4
|
# This program is free software; you can redistribute it and/or
|
5
|
# modify it under the terms of the GNU General Public License
|
6
|
# as published by the Free Software Foundation; either version 2
|
7
|
# of the License, or (at your option) any later version.
|
8
|
#
|
9
|
# This program is distributed in the hope that it will be useful,
|
10
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
# GNU General Public License for more details.
|
13
|
#
|
14
|
# You should have received a copy of the GNU General Public License
|
15
|
# along with this program; if not, write to the Free Software
|
16
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
|
|
18
|
# This class is intended to do the conversion of trac wiki content
|
19
|
# into Redmine wiki content. This is needed cause
|
20
|
# trac wiki and Redmine wiki have different markup languages.
|
21
|
|
22
|
module TracMigrate
|
23
|
class TracWiki
|
24
|
|
25
|
public
|
26
|
|
27
|
# This will hold the renumbered ticket numbers
|
28
|
# of trac.
|
29
|
@@ticket_map = []
|
30
|
|
31
|
def TracWiki.ticketmap(ticket, issue)
|
32
|
@@ticket_map[ticket] = issue
|
33
|
end
|
34
|
|
35
|
def TracWiki.ticketmap
|
36
|
return @@ticket_map
|
37
|
end
|
38
|
|
39
|
# This method will do the whole conversion between
|
40
|
# trac wiki and Redmine wiki.
|
41
|
#
|
42
|
def TracWiki.wiki(text)
|
43
|
|
44
|
# Titles
|
45
|
text = text.gsub(/^(\=+)\s(.+)\s(\=+)/) {|s| "\nh#{$1.length}. #{$2}\n"}
|
46
|
|
47
|
# External Links
|
48
|
text = text.gsub(/\[(http[^\s]+)\s+([^\]]+)\]/) {|s| "\"#{$2}\":#{$1}"}
|
49
|
|
50
|
text = linebreak(text)
|
51
|
|
52
|
# Do ticket extractions and renumbering.
|
53
|
text = ticket_links(text)
|
54
|
|
55
|
# Do mailto extraction and conversion
|
56
|
text = mailto_links(text)
|
57
|
|
58
|
# Usual wiki links
|
59
|
text = wiki_links(text)
|
60
|
|
61
|
# Links to pages UsingJustWikiCaps
|
62
|
text = text.gsub(/([^!]|^)(^| )([A-Z][a-z]+[A-Z][a-zA-Z]+)/, '\\1\\2[[\3]]')
|
63
|
# Normalize things that were supposed to not be links
|
64
|
# like !NotALink
|
65
|
text = text.gsub(/(^| )!([A-Z][A-Za-z]+)/, '\1\2')
|
66
|
|
67
|
# Do the changeset link conversion
|
68
|
text = changeset_links(text)
|
69
|
|
70
|
#Do the code highlighting stuff.
|
71
|
text = code_highlighting(text)
|
72
|
|
73
|
# emphasize etc.
|
74
|
text = highlight(text)
|
75
|
|
76
|
# different kind of lists.
|
77
|
text = lists(text)
|
78
|
|
79
|
# Table stuff
|
80
|
text = tables(text)
|
81
|
|
82
|
# Links to source area (repository browser in trac)
|
83
|
text = source_links(text)
|
84
|
|
85
|
# Links to versions in Redmine (trac milestones)
|
86
|
text = milestone_links(text)
|
87
|
|
88
|
#TODO: Blockquotes ?
|
89
|
#TODO: http://trac.edgewall/wiki/WikiRestructuredText#BiggerReSTExample
|
90
|
end
|
91
|
|
92
|
private
|
93
|
|
94
|
# This method will convert code highlighting
|
95
|
# of trac where {{{ and }}} is used to separate
|
96
|
# it from the usual wiki content.
|
97
|
# The markers {{{ and }}} must be on separate lines
|
98
|
# to indicate an code part. If they are
|
99
|
# on the same line this is defined to create
|
100
|
# text with monospace.
|
101
|
#TODO: {{{Text}}} is currently not correctly converted!!! this is `monospace` too!
|
102
|
#
|
103
|
def TracWiki.code_highlighting(text)
|
104
|
# We would like to convert the Code highlighting too
|
105
|
# This will go into the next line.
|
106
|
shebang_line = false
|
107
|
# Reguar expression for start of code
|
108
|
pre_re = /^\{\{\{$/
|
109
|
# Code hightlighing...
|
110
|
shebang_re = /^\#\!([a-z]+)/
|
111
|
# Regular expression for end of code
|
112
|
pre_end_re = /^\}\}\}$/
|
113
|
|
114
|
# Go through the whole text..extract it line by line
|
115
|
text = text.gsub(/^(.*)$/) do |line|
|
116
|
m_pre = pre_re.match(line)
|
117
|
if m_pre
|
118
|
line = '<pre>'
|
119
|
else
|
120
|
m_sl = shebang_re.match(line)
|
121
|
if m_sl
|
122
|
shebang_line = true
|
123
|
line = '<code class="' + m_sl[1] + '">'
|
124
|
end
|
125
|
m_pre_end = pre_end_re.match(line)
|
126
|
if m_pre_end
|
127
|
line = '</pre>'
|
128
|
if shebang_line
|
129
|
line = '</code>' + line
|
130
|
end
|
131
|
end
|
132
|
end
|
133
|
line
|
134
|
end
|
135
|
end
|
136
|
|
137
|
# Things like _Text_ '''''AAA''''' etc.
|
138
|
#
|
139
|
def TracWiki.highlight(text)
|
140
|
# Highlighting
|
141
|
# bold italic
|
142
|
text = text.gsub(/'''''([^\s])/, '_*\1')
|
143
|
# bold italic
|
144
|
text = text.gsub(/([^\s])'''''/, '\1*_')
|
145
|
# bold
|
146
|
text = text.gsub(/'''/, '*')
|
147
|
# italic
|
148
|
text = text.gsub(/''/, '_')
|
149
|
# underline.
|
150
|
text = text.gsub(/__/, '+')
|
151
|
# stike-through
|
152
|
text = text.gsub(/~~/, '-')
|
153
|
# monospace
|
154
|
text = text.gsub(/`/, '@')
|
155
|
# subscript
|
156
|
text = text.gsub(/,,/, '~')
|
157
|
#TODO: superscript => CHECK HOW THIS IS DONE IN REDMINE
|
158
|
#text = text.gsub(//, '~')
|
159
|
end
|
160
|
|
161
|
# The lists will be converted.
|
162
|
#
|
163
|
def TracWiki.lists(text)
|
164
|
# Lists
|
165
|
text = text.gsub(/^([ ]+)\* /) {|s| '*' * $1.length + " "}
|
166
|
#TODO: definition list => trac manual
|
167
|
#TODO: unordered lists (1. 2. etc.)
|
168
|
end
|
169
|
|
170
|
# This method will do the conversion of
|
171
|
# all ticket entries.
|
172
|
# Here we do a renumbering of the ticket
|
173
|
# numbers into appropiate issue numbers of redmine.
|
174
|
#
|
175
|
#TODO: Check the ticket re-writing in the first three cases; should be done too!
|
176
|
def TracWiki.ticket_links(text)
|
177
|
# Situations like the following:
|
178
|
# - [ticket:234 Text],[ticket:234 This is a test]
|
179
|
# Hints: This is a little hack, cause in Redmine it seemed not to be
|
180
|
# possible to have a link to an issue with different text like
|
181
|
# in Trac. So this uses the URL syntax to make a link to the
|
182
|
# particular issue
|
183
|
text = text.gsub(/\[ticket\:([^\ ]+)\ (.+?)\]/, '"\2":/issues/show/\1')
|
184
|
|
185
|
# Situations like the following:
|
186
|
# - [ticket:234]
|
187
|
text = text.gsub(/\[ticket\:([^\ ]+)\]/, '#\1')
|
188
|
|
189
|
# Situations like:
|
190
|
# - ticket:1234
|
191
|
# - #1 is working cause Redmine uses the same syntax.
|
192
|
text = text.gsub(/ticket\:([^\ ]+)/, '#\1')
|
193
|
|
194
|
# Ticket number re-writing
|
195
|
text = text.gsub(/#(\d+)/) do |s|
|
196
|
if $1.length < 10
|
197
|
@@ticket_map[$1.to_i] ||= $1
|
198
|
"\##{@@ticket_map[$1.to_i] || $1}"
|
199
|
else
|
200
|
s
|
201
|
end
|
202
|
end
|
203
|
end
|
204
|
|
205
|
# This will convert the links to revisions
|
206
|
# or in Subversion terms Changesets.
|
207
|
#
|
208
|
def TracWiki.changeset_links(text)
|
209
|
# changeset links [123]
|
210
|
text = text.gsub(/\[(\d+)\]/, 'r\1')
|
211
|
# changeset:122
|
212
|
text = text.gsub(/changeset\:(\d+)/, 'r\1')
|
213
|
# r123 => r123 (No conversion needed.
|
214
|
#text = text.gsub(/r(\d+)/, 'r\1')
|
215
|
end
|
216
|
|
217
|
# This method will do the conversion of mailto entries
|
218
|
# in trac which will be converted to Redmine syntax.
|
219
|
#
|
220
|
def TracWiki.mailto_links(text)
|
221
|
# Situations like:
|
222
|
# - [mailto:user@test.de]
|
223
|
text = text.gsub(/\[mailto\:([^\ ]+)\]/, '\1')
|
224
|
# - [mailto:user@test.de This is the text]
|
225
|
# - Here we use a hack to have a different text in relationship
|
226
|
# with an email address.
|
227
|
text = text.gsub(/\[mailto\:([^\ ]+)\ (.+?)\]/, '"\2":mailto:\1')
|
228
|
end
|
229
|
|
230
|
# This will convert the milestone references from trac to redmine.
|
231
|
#
|
232
|
def TracWiki.milestone_links(text)
|
233
|
# First Situation:
|
234
|
# - [milestone:"0.1.0 Mercury" Milestone 0.1.0 (Mercury)]
|
235
|
# Hint: The text "Milestone 0.1.0 (Mercury)" is not converted,
|
236
|
# cause Redmine's wiki does not support this.
|
237
|
#TODO: May be we can use a hack to convert into something visual identical
|
238
|
text = text.gsub(/\[milestone\:\"([^\"]+)\"\ (.+?)\]/, 'version:"\1"')
|
239
|
|
240
|
# Second Situation:
|
241
|
# [milestone:"0.1.0 Mercury"]
|
242
|
# milestone:"0.1.2 Mercury"
|
243
|
text = text.gsub(/\[milestone\:\"([^\"]+)\"\]/, 'version:"\1"')
|
244
|
text = text.gsub(/milestone\:\"([^\"]+)\"/, 'version:"\1"')
|
245
|
# Third Situation:
|
246
|
# [milestone:0.1.0]
|
247
|
text = text.gsub(/\[milestone\:([^\ ]+)\]/, 'version:\1')
|
248
|
# Forth situation:
|
249
|
# milestone:xyzabc
|
250
|
text = text.gsub(/milestone\:([^\ ]+)/, 'version:\1')
|
251
|
end
|
252
|
|
253
|
# This will convert source code links. In trac
|
254
|
# these are links to the repository browser.
|
255
|
#
|
256
|
def TracWiki.source_links(text)
|
257
|
# Links to repository browser trac: source:/some/path/file@123
|
258
|
# source:/some/path/file@123#L10
|
259
|
|
260
|
# Example 1:
|
261
|
# [source:/tags/JAGOSI-0.0.10/jagosiapi/src/main/java/com/soebes/jagosi/api/JaGoSI.java@latest#L626 Line 626]
|
262
|
text = text.gsub(/\[source\:(\/[a-zA-Z0-9_\/\.\-]+)(\@latest)#L(\d+) (.*?)\]/, 'source:\1#L\3')
|
263
|
text = text.gsub(/\[source\:(\/[a-zA-Z0-9_\/\.\-]+)\@(\d+)#L(\d+) (.*?)\]/, 'source:\1@\2#L\3')
|
264
|
end
|
265
|
|
266
|
# The usual wiki links
|
267
|
#
|
268
|
def TracWiki.wiki_links(text)
|
269
|
# ["Text" xxxxx]
|
270
|
text = text.gsub(/\[\"(.+)\".*\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
|
271
|
# [wiki:"text text" more text]
|
272
|
text = text.gsub(/\[wiki:\"(.+)\".*\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
|
273
|
#
|
274
|
text = text.gsub(/\[wiki:\"(.+)\".*\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
|
275
|
text = text.gsub(/\[wiki:([^\s\]]+)\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
|
276
|
text = text.gsub(/\[wiki:([^\s\]]+)\s(.*)\]/) {|s| "[[#{$1.delete(',./?;|:')}|#{$2.delete(',./?;|:')}]]"}
|
277
|
end
|
278
|
|
279
|
# This will convert the particular line breaks in trac
|
280
|
# into simple line breaks.
|
281
|
#
|
282
|
def TracWiki.linebreak(text)
|
283
|
# line break trac support both ways.
|
284
|
text = text.gsub(/\[\[(BR|br)\]\]/, "\n") # This has to go before the rules below
|
285
|
end
|
286
|
|
287
|
# Currently we will only convert the simple
|
288
|
# situation ||X||YY||ZZ||
|
289
|
# Not converted will be: empty lines (trac will ignore them)
|
290
|
# Formatting left, right alignment etc.
|
291
|
#TODO: Support alignment etc.
|
292
|
def TracWiki.tables(text)
|
293
|
# Tables
|
294
|
text = text.gsub(/\|\|/, '|')
|
295
|
end
|
296
|
end
|
297
|
end
|