trac_migration.rb

Karl Heinz Marbaise, 2008-10-30 22:15

Download (10.6 KB)

 
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
        text = text.gsub(/(\n|\r)(\n|\r)?/, "\n")
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
        # Do the changeset link conversion
62
        text = changeset_links(text)
63
  
64
        # First see if we have to convert something as monospace.
65
        text = code_monospace(text)
66

    
67
        #Do the code highlighting stuff.
68
        text = code_highlighting(text)
69

    
70
        # emphasize etc.
71
        text = highlight(text)
72

    
73
        # different kind of lists.
74
        text = lists(text)
75

    
76
        # Table stuff
77
        text = tables(text)
78
  
79
        # Links to source area (repository browser in trac)
80
        text = source_links(text)
81
  
82
        # Links to versions in Redmine (trac milestones)
83
        text = milestone_links(text)
84

    
85
        # Links to pages UsingJustWikiCaps
86
        text = text.gsub(/([^!]|^)(^| )([A-Z][a-z]+[A-Z][a-zA-Z]+)/, '\\1\\2[[\3]]')
87
        # Normalize things that were supposed to not be links
88
        # like !NotALink
89
        text = text.gsub(/(^| )!([A-Z][A-Za-z]+)/, '\1\2')
90
  
91
#TODO: Blockquotes ?
92
#TODO: http://trac.edgewall/wiki/WikiRestructuredText#BiggerReSTExample
93
      end
94
  
95
    private
96

    
97
      # This will convert the trac monospace marker
98
      # into Redmine's one (currently inline code).
99
#TODO: Check to see if a better choice exists?
100
      #
101
      def TracWiki.code_monospace(text)
102
        text = text.gsub(/\{\{\{(.*?)\}\}\}/, '@\1@')
103
      end
104

    
105
      # This method will convert code highlighting
106
      # of trac where {{{ and }}} is used to separate
107
      # it from the usual wiki content.
108
      # A shebang line can be used to indicate a particular 
109
      # code high lighter in Trac (#!java etc.)
110
      # 
111
# TODO: Add warnings if we have situations which can't be converted
112
#      unknown or not supported code tags!      
113
      def TracWiki.code_highlighting(text)
114
        # We would like to convert the Code highlighting too
115
        # This will go into the next line.
116

    
117
        shebang_line = false
118
        if text =~/^\{\{\{(\n|\r)(\n|\r)?\#\![a-z]+(\n|\r)(\n|\r)?/m
119
          text = text.gsub(/^\{\{\{(\n|\r)(\n|\r)?\#\!([a-z]+)(\n|\r)(\n|\r)?/m, '<pre><code class="\3">')
120
          shebang_line = true 
121
        end
122

    
123
        text = text.gsub(/^\{\{\{/, '<pre>')
124
        
125
        if shebang_line
126
          text = text.gsub(/^\}\}\}/, '</code></pre>')
127
        else
128
          text = text.gsub(/^\}\}\}/, '</pre>')
129
        end
130
      end
131
      
132
      # Things like _Text_ '''''AAA''''' etc. 
133
      #
134
      def TracWiki.highlight(text)
135
        # Highlighting
136
        # bold italic
137
        text = text.gsub(/'''''([^\s])/, '_*\1')
138
        # bold italic
139
        text = text.gsub(/([^\s])'''''/, '\1*_')
140
        # bold
141
        text = text.gsub(/'''/, '*')
142
        # italic
143
        text = text.gsub(/''/, '_')
144
        # underline.
145
        text = text.gsub(/__/, '+')
146
        # stike-through
147
        text = text.gsub(/~~/, '-')
148
        # monospace
149
        text = text.gsub(/`/, '@')
150
        # subscript
151
        text = text.gsub(/,,/, '~')
152
# TODO: superscript => CHECK HOW THIS IS DONE IN REDMINE
153
        #text = text.gsub(//, '~')
154
      end
155
      
156
      # The lists will be converted.
157
      #
158
      def TracWiki.lists(text)
159
        # Lists
160
        text = text.gsub(/^([ ]+)\* /) {|s| '*' * $1.length + " "}
161
# TODO: definition list => trac manual
162
# TODO: unordered lists (1. 2. etc.)
163
      end
164

    
165
      # This method will do the conversion of
166
      # all ticket entries.
167
      # Here we do a renumbering of the ticket
168
      # numbers into appropiate issue numbers of redmine.
169
      #
170
#TODO: Check the ticket re-writing in the first three cases; should be done too!
171
      def TracWiki.ticket_links(text)
172
        # Situations like the following:
173
        #      - [ticket:234 Text],[ticket:234 This is a test]
174
        # Hints: This is a little hack, cause in Redmine it seemed not to be 
175
        #        possible to have a link to an issue with different text like
176
        #        in Trac. So this uses the URL syntax to make a link to the 
177
        #        particular issue
178
        text = text.gsub(/\[ticket\:([^\ ]+)\ (.+?)\]/, '"\2":/issues/show/\1')
179

    
180
        # Situations like the following:
181
        #      - [ticket:234]
182
        text = text.gsub(/\[ticket\:([^\ ]+)\]/, '#\1')
183
        
184
        # Situations like:
185
        #      - ticket:1234
186
        #      - #1 is working cause Redmine uses the same syntax.
187
        text = text.gsub(/ticket\:([^\ ]+)/, '#\1')
188
        
189
        # Ticket number re-writing
190
        text = text.gsub(/#(\d+)/) do |s|
191
          if $1.length < 10
192
            @@ticket_map[$1.to_i] ||= $1
193
            "\##{@@ticket_map[$1.to_i] || $1}"
194
          else
195
            s
196
          end
197
        end
198
      end
199
      
200
      # This will convert the links to revisions
201
      # or in Subversion terms Changesets.
202
      #
203
      def TracWiki.changeset_links(text)
204
        # changeset links [123]
205
        text = text.gsub(/\[(\d+)\]/, 'r\1')
206
        # changeset:122
207
        text = text.gsub(/changeset\:(\d+)/, 'r\1')
208
        # r123 => r123 (No conversion needed.
209
        #text = text.gsub(/r(\d+)/, 'r\1')
210
      end
211
      
212
      # This method will do the conversion of mailto entries
213
      # in trac which will be converted to Redmine syntax.
214
      #
215
      def TracWiki.mailto_links(text)
216
        # Situations like:
217
        #      - [mailto:user@test.de]
218
        text = text.gsub(/\[mailto\:([^\ ]+)\]/, '\1')
219
        #      - [mailto:user@test.de This is the text]
220
        #      - Here we use a hack to have a different text in relationship
221
        #        with an email address.
222
        text = text.gsub(/\[mailto\:([^\ ]+)\ (.+?)\]/, '"\2":mailto:\1')
223
      end
224
      
225
      # This will convert the milestone references from trac to redmine.
226
      #
227
      def TracWiki.milestone_links(text)
228
        # First Situation:
229
        #      - [milestone:"0.1.0 Mercury" Milestone 0.1.0 (Mercury)]
230
        # Hint: The text "Milestone 0.1.0 (Mercury)" is not converted,
231
        #      cause Redmine's wiki does not support this.
232
#TODO: May be we can use a hack to convert into something visual identical
233
        text = text.gsub(/\[milestone\:\"([^\"]+)\"\ (.+?)\]/, 'version:"\1"')
234
  
235
        # Second Situation:
236
        #      [milestone:"0.1.0 Mercury"]
237
        #       milestone:"0.1.2 Mercury"
238
        text = text.gsub(/\[milestone\:\"([^\"]+)\"\]/, 'version:"\1"')
239
        text = text.gsub(/milestone\:\"([^\"]+)\"/, 'version:"\1"')
240
        # Third Situation:
241
        #      [milestone:0.1.0]
242
        text = text.gsub(/\[milestone\:([^\ ]+)\]/, 'version:\1')
243
        # Forth situation:
244
        #      milestone:xyzabc
245
        text = text.gsub(/milestone\:([^\ ]+)/, 'version:\1')
246
      end
247
  
248
      # This will convert source code links. In trac
249
      # these are links to the repository browser.
250
      #
251
      def TracWiki.source_links(text)
252
        # Links to repository browser trac:   source:/some/path/file@123
253
        #                                     source:/some/path/file@123#L10
254
  
255
        # Example 1:
256
        #    [source:/tags/JAGOSI-0.0.10/jagosiapi/src/main/java/com/soebes/jagosi/api/JaGoSI.java@latest#L626 Line 626]
257
        text = text.gsub(/\[source\:([a-zA-Z0-9_\/\.\-]+)(\@latest)#L(\d+) (.*?)\]/, 'source:\1@HEAD#L\3')
258

    
259
        # Example 2:
260
        #    [source:/tags/JAGOSI-0.0.10/jagosiapi/src/main/java/com/soebes/jagosi/api/JaGoSI.java@699#L626 Line 626]
261
        text = text.gsub(/\[source\:([a-zA-Z0-9_\/\.\-]+)\@(\d+)#L(\d+) (.*?)\]/, 'source:\1@\2#L\3')
262
        
263
        # Example 3:
264
        #    [source:/trunk/jagosiclient This is Text]
265
        # Hint: This is a hack to make it possible to link sources with different text.
266
        #       This seemed to be not possible in Redmine.
267
#TODO: Check this
268
        text = text.gsub(/\[source\:([a-zA-Z0-9_\/\.\-]+) (.*?)\]/, '"\2":/repositories/browse/\1')
269
      end
270
    
271
      # The usual wiki links
272
      #
273
      def TracWiki.wiki_links(text)
274
        # ["Text" xxxxx]
275
        text = text.gsub(/\[\"(.+)\".*\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
276
        # [wiki:"text text" more text]
277
        text = text.gsub(/\[wiki:\"(.+)\".*\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
278
        # 
279
        text = text.gsub(/\[wiki:\"(.+)\".*\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
280
        text = text.gsub(/\[wiki:([^\s\]]+)\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
281
        text = text.gsub(/\[wiki:([^\s\]]+)\s(.*)\]/) {|s| "[[#{$1.delete(',./?;|:')}|#{$2.delete(',./?;|:')}]]"}
282
      end
283

    
284
      # This will convert the particular line breaks in trac
285
      # into simple line breaks.
286
      #
287
      def TracWiki.linebreak(text)
288
        # line break trac support both ways.
289
        text = text.gsub(/\[\[(BR|br)\]\]/, "\n") # This has to go before the rules below
290
      end
291

    
292
      # Currently we will only convert the simple
293
      # situation ||X||YY||ZZ||
294
      # Not converted will be: empty lines (trac will ignore them)
295
      # Formatting left, right alignment etc.
296
#TODO: Support alignment etc.
297
      def TracWiki.tables(text)
298
        # Tables
299
        text = text.gsub(/\|\|/, '|')
300
      end
301
  end
302
end
303