Project

General

Profile

RE: Implementing Some Unit Test / Fixing Some Patches etc. » trac_migration.rb

The Class TracWiki - Karl Heinz Marbaise, 2008-10-27 22:26

 
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
(1-1/2)