# redMine - project management software # Copyright (C) 2008 Karl Heinz Marbaise # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # This class is intended to do the conversion of trac wiki content # into Redmine wiki content. This is needed cause # trac wiki and Redmine wiki have different markup languages. module TracMigrate class TracWiki public # This will hold the renumbered ticket numbers # of trac. @@ticket_map = [] def TracWiki.ticketmap(ticket, issue) @@ticket_map[ticket] = issue end def TracWiki.ticketmap return @@ticket_map end # This method will do the whole conversion between # trac wiki and Redmine wiki. # def TracWiki.wiki(text) text = text.gsub(/(\n|\r)(\n|\r)?/, "\n") # Titles text = text.gsub(/^(\=+)\s(.+)\s(\=+)/) {|s| "\nh#{$1.length}. #{$2}\n"} # External Links text = text.gsub(/\[(http[^\s]+)\s+([^\]]+)\]/) {|s| "\"#{$2}\":#{$1}"} text = linebreak(text) # Do ticket extractions and renumbering. text = ticket_links(text) # Do mailto extraction and conversion text = mailto_links(text) # Usual wiki links text = wiki_links(text) # Do the changeset link conversion text = changeset_links(text) # First see if we have to convert something as monospace. text = code_monospace(text) #Do the code highlighting stuff. text = code_highlighting(text) # emphasize etc. text = highlight(text) # different kind of lists. text = lists(text) # Table stuff text = tables(text) # Links to source area (repository browser in trac) text = source_links(text) # Links to versions in Redmine (trac milestones) text = milestone_links(text) # links to attachments text = attachment_links(text) # Links to pages UsingJustWikiCaps text = text.gsub(/([^!]|^)(^| )([A-Z][a-z]+[A-Z][a-zA-Z]+)/, '\\1\\2[[\3]]') # Normalize things that were supposed to not be links # like !NotALink text = text.gsub(/(^| )!([A-Z][A-Za-z]+)/, '\1\2') #TODO: Blockquotes ? #TODO: http://trac.edgewall/wiki/WikiRestructuredText#BiggerReSTExample end private # This will convert the trac monospace marker # into Redmine's one (currently inline code). #TODO: Check to see if a better choice exists? # def TracWiki.code_monospace(text) text = text.gsub(/\{\{\{(.*?)\}\}\}/, '@\1@') end # This method will convert code highlighting # of trac where {{{ and }}} is used to separate # it from the usual wiki content. # A shebang line can be used to indicate a particular # code high lighter in Trac (#!java etc.) # # TODO: Add warnings if we have situations which can't be converted # unknown or not supported code tags! def TracWiki.code_highlighting(text) # We would like to convert the Code highlighting too # This will go into the next line. shebang_line = false if text =~/^\{\{\{(\n|\r)(\n|\r)?\#\![a-z]+(\n|\r)(\n|\r)?/m text = text.gsub(/^\{\{\{(\n|\r)(\n|\r)?\#\!([a-z]+)(\n|\r)(\n|\r)?/m, '
')
shebang_line = true
end
text = text.gsub(/^\{\{\{/, '')
if shebang_line
text = text.gsub(/^\}\}\}/, '
')
else
text = text.gsub(/^\}\}\}/, '')
end
end
# Things like _Text_ '''''AAA''''' etc.
#
def TracWiki.highlight(text)
# Highlighting
# bold italic
text = text.gsub(/'''''([^\s])/, '_*\1')
# bold italic
text = text.gsub(/([^\s])'''''/, '\1*_')
# bold
text = text.gsub(/'''/, '*')
# italic
text = text.gsub(/''/, '_')
# underline.
text = text.gsub(/__/, '+')
# stike-through
text = text.gsub(/~~/, '-')
# monospace
text = text.gsub(/`/, '@')
# subscript
text = text.gsub(/,,/, '~')
# TODO: superscript => CHECK HOW THIS IS DONE IN REDMINE
#text = text.gsub(//, '~')
end
# The lists will be converted.
#
def TracWiki.lists(text)
# Lists
text = text.gsub(/^([ ]+)\* /) {|s| '*' * $1.length + " "}
# TODO: definition list => trac manual
# TODO: unordered lists (1. 2. etc.)
end
# This method will do the conversion of
# all ticket entries.
# Here we do a renumbering of the ticket
# numbers into appropiate issue numbers of redmine.
#
#TODO: Check the ticket re-writing in the first three cases; should be done too!
def TracWiki.ticket_links(text)
# Situations like the following:
# - [ticket:234 Text],[ticket:234 This is a test]
# Hints: This is a little hack, cause in Redmine it seemed not to be
# possible to have a link to an issue with different text like
# in Trac. So this uses the URL syntax to make a link to the
# particular issue
text = text.gsub(/\[ticket\:([^\ ]+)\ (.+?)\]/, '"\2":/issues/show/\1')
# Situations like the following:
# - [ticket:234]
text = text.gsub(/\[ticket\:([^\ ]+)\]/, '#\1')
# Situations like:
# - ticket:1234
# - #1 is working cause Redmine uses the same syntax.
text = text.gsub(/ticket\:([^\ ]+)/, '#\1')
# Ticket number re-writing
text = text.gsub(/#(\d+)/) do |s|
if $1.length < 10
@@ticket_map[$1.to_i] ||= $1
"\##{@@ticket_map[$1.to_i] || $1}"
else
s
end
end
end
# This will convert the links to revisions
# or in Subversion terms Changesets.
#
def TracWiki.changeset_links(text)
# changeset links [123]
text = text.gsub(/\[(\d+)\]/, 'r\1')
# changeset:122
text = text.gsub(/changeset\:(\d+)/, 'r\1')
# r123 => r123 (No conversion needed.
#text = text.gsub(/r(\d+)/, 'r\1')
end
# This method will do the conversion of mailto entries
# in trac which will be converted to Redmine syntax.
#
def TracWiki.mailto_links(text)
# Situations like:
# - [mailto:user@test.de]
text = text.gsub(/\[mailto\:([^\ ]+)\]/, '\1')
# - [mailto:user@test.de This is the text]
# - Here we use a hack to have a different text in relationship
# with an email address.
text = text.gsub(/\[mailto\:([^\ ]+)\ (.+?)\]/, '"\2":mailto:\1')
end
# This will convert the milestone references from trac to redmine.
#
def TracWiki.milestone_links(text)
# First Situation:
# - [milestone:"0.1.0 Mercury" Milestone 0.1.0 (Mercury)]
# Hint: The text "Milestone 0.1.0 (Mercury)" is not converted,
# cause Redmine's wiki does not support this.
#TODO: May be we can use a hack to convert into something visual identical
text = text.gsub(/\[milestone\:\"([^\"]+)\"\ (.+?)\]/, 'version:"\1"')
# Second Situation:
# [milestone:"0.1.0 Mercury"]
# milestone:"0.1.2 Mercury"
text = text.gsub(/\[milestone\:\"([^\"]+)\"\]/, 'version:"\1"')
text = text.gsub(/milestone\:\"([^\"]+)\"/, 'version:"\1"')
# Third Situation:
# [milestone:0.1.0]
text = text.gsub(/\[milestone\:([^\ ]+)\]/, 'version:\1')
# Forth situation:
# milestone:xyzabc
text = text.gsub(/milestone\:([^\ ]+)/, 'version:\1')
end
# This will convert source code links. In trac
# these are links to the repository browser.
#
def TracWiki.source_links(text)
# Links to repository browser trac: source:/some/path/file@123
# source:/some/path/file@123#L10
# Example 1:
# [source:/tags/JAGOSI-0.0.10/jagosiapi/src/main/java/com/soebes/jagosi/api/JaGoSI.java@latest#L626 Line 626]
text = text.gsub(/\[source\:([a-zA-Z0-9_\/\.\-]+)(\@latest)#L(\d+) (.*?)\]/, 'source:\1#L\3')
# Example 2:
# [source:/tags/JAGOSI-0.0.10/jagosiapi/src/main/java/com/soebes/jagosi/api/JaGoSI.java@699#L626 Line 626]
text = text.gsub(/\[source\:([a-zA-Z0-9_\/\.\-]+)\@(\d+)#L(\d+) (.*?)\]/, 'source:\1@\2#L\3')
# Example 3:
# [source:/trunk/jagosiclient This is Text]
# Hint: This is a hack to make it possible to link sources with different text.
# This seemed to be not possible in Redmine.
#TODO: Check this. There must be added the project identifier to get working links.
text = text.gsub(/\[source\:([a-zA-Z0-9_\/\.\-]+) (.*?)\]/, '"\2":/repositories/browse/\1')
end
# Attachments within wiki pages
#
# In trac the following parts are valid:
# attachment:the_file.txt creates a link to the attachment the_file.txt of the current object
# attachment:wiki:MyPage:the_file.txt creates a link to the attachment the_file.txt of the MyPage wiki page
# attachment:ticket:753:the_file.txt creates a link to the attachment the_file.txt of the ticket 753
def TracWiki.attachment_links(text)
# [attachment:JaGoSIAPI-0.0.10.jar] => attachment:JaGoSIAPI-0.0.10.jar
text = text.gsub(/\[attachment\:([a-zA-Z0-9_\/\.\-]+)\]/, 'attachment:\1')
# [attachment:JaGoSIAPI-0.0.10.jar This is text] => "This is texgt":attachment:JaGoSIAPI-0.0.10.jar
text = text.gsub(/\[attachment\:([a-zA-Z0-9_\/\.\-]+) (.*?)\]/, '"\2":attachment:\1')
# attachment:wiki:MyPage:the_file.txt
#TODO: Currently not supported.
# attachment:ticket:643:the_file.txt
#TODO: Currently not supported.
#
end
# The usual wiki links
#
def TracWiki.wiki_links(text)
# [wiki:"This is Text"]
# [wiki:"String WikiString"]
text = text.gsub(/\[wiki\:"([^\"]+)\"\]/, '[[\1]]')
# ["Text" xxxxx]
text = text.gsub(/\[\"(.+)\".*?\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
# [wiki:"text text" more text]
text = text.gsub(/\[wiki:\"(.+)\".*?\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
#
text = text.gsub(/\[wiki:\"(.+)\".*?\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
text = text.gsub(/\[wiki:([^\s\]]+)\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
text = text.gsub(/\[wiki:([^\s\]]+)\s(.*?)\]/) {|s| "[[#{$1.delete(',./?;|:')}|#{$2.delete(',./?;|:')}]]"}
end
# This will convert the particular line breaks in trac
# into simple line breaks.
#
def TracWiki.linebreak(text)
# line break trac support both ways.
text = text.gsub(/\[\[(BR|br)\]\]/, "\n") # This has to go before the rules below
end
# Currently we will only convert the simple
# situation ||X||YY||ZZ||
# Not converted will be: empty lines (trac will ignore them)
# Formatting left, right alignment etc.
#TODO: Support alignment etc.
def TracWiki.tables(text)
# Tables
text = text.gsub(/\|\|/, '|')
end
end
end