require 'active_record' require 'iconv' require 'pp' namespace :redmine do desc 'MoinMoin migration script' task :migrate_from_moinmoin => :environment do module MMMigrate def self.migrate puts "No wiki defined" unless @target_project.wiki wiki = @target_project.wiki || Wiki.new(:project => @target_project, :start_page => @target_project.name) mm = MoinMoinWiki.new(@moin_moin_path) mm.each_page do |page| new_title = page['title'] p = wiki.find_or_new_page(new_title) page['revisions'].each_with_index do |revision, i| p.content = WikiContent.new(:page => p) if p.new_record? content = p.content_for_version(i) content.text = self.convert_wiki_text(revision) content.author = User.find_by_mail("admin@example.com") content.comments = "Revision %d from MoinMoin." % i puts "Title: " + new_title #puts " Text: " + content.text puts " Comment: " + p.content.comments p.new_record? ? p.save : content.save end end end class MoinMoinWiki def initialize(path) @path = path end def process_page(folder) fpath = @path + "/" + folder + "/" r = {} r['title'] = folder r['revisions'] = [] rev_names = Dir.entries(fpath + "revisions").reject { |e| e == "." || e == ".." } rev_names.sort.each do |revision| r['revisions'] << IO.read(fpath + "revisions" + "/" + revision) end r end def each_page() Dir.entries(@path).reject {|e| e == ".." || e == "."}.select{|e| File.directory? @path + "/" + e}.each do |page_folder| # Is it a valid page? next unless Dir.entries(@path + "/" + page_folder).include?("revisions") yield process_page(page_folder) end end end def self.target_project_identifier(identifier) project = Project.find_by_identifier(identifier) if !project die else puts "Found Project: " + project.to_yaml end @target_project = project.new_record? ? nil : project end def self.target_moin_moin_path(path) @moin_moin_path = path end def self.find_or_create_user(email, project_member = false) u = User.find_by_mail(email) if !u u = User.find_by_mail(@@mw_default_user) end if(!u) # Create a new user if not found mail = email[0,limit_for(User, 'mail')] mail = "#{mail}@fortna.com" unless mail.include?("@") name = email[0,email.index("@")]; u = User.new :firstname => name[0,limit_for(User, 'firstname')].gsub(/[^\w\s\'\-]/i, '-'), :lastname => '-', :mail => mail.gsub(/[^-@a-z0-9\.]/i, '-') u.login = email[0,limit_for(User, 'login')].gsub(/[^a-z0-9_\-@\.]/i, '-') u.password = 'bugzilla' u.admin = false # finally, a default user is used if the new user is not valid puts "Created User: "+ u.to_yaml u = User.find(:first) unless u.save else puts "Found User: " + u.to_yaml end # Make sure he is a member of the project if project_member && !u.member_of?(@target_project) role = ROLE_MAPPING['developer'] Member.create(:user => u, :project => @target_project, :role => role) u.reload end u end # Basic wiki syntax conversion def self.convert_wiki_text(text) # Titles text = text.gsub(/^(\=+)\s*([^=]+)\s*\=+\s*$/) {|s| "\nh#{$1.length}. #{$2}\n"} # Internal links text = text.gsub(/\[\[(.*)\s+\|(.*)\]\]/) {|s| "[[#{$1}|#{$2}]]"} # External Links text = text.gsub(/\[(http[^\s]+)\s+([^\]]+)\]/) {|s| "\"#{$2}\":#{$1}"} text = text.gsub(/\[(http[^\s]+)\]/) {|s| "#{$1}"} # Highlighting text = text.gsub(/'''''([^\s])/, '_*\1') text = text.gsub(/([^\s])'''''/, '\1*_') text = text.gsub(/'''([^\s])/, '*\1') text = text.gsub(/([^\s])'''/, '\1*') text = text.gsub(/''([^\s])/, '_*\1') text = text.gsub(/([^\s])''/, '\1*_') # code #text = text.gsub(/((^ [^\n]*\n)+)/m) { |s| "
\n#{$1}\n" }
#text = text.gsub(/(^\n^ .*?$)/m) { |s| "#{$1}" }
#text = text.gsub(/(^ .*?\n)\n/m) { |s| "#{$1}\n" }
text = text.gsub(/\{\{\{\s*$/) { |s| "" }
text = text.gsub(/\}\}\}\s*$/) { |s| "\n" }
text = text.gsub(/\{\{\{/) { |s| "" }
text = text.gsub(/\}\}\}/) { |s| "" }
# Some silly leading whitespace.
text = text.gsub(/\n/m) { |s| "" }
# Tables
# Half-assed attempt
# First strip off the table formatting
text = text.gsub(/^\![^\|]*/, '')
text = text.gsub(/^\{\|[^\|]*$/, '{|')
# Now congeal the rows
while( text.gsub!(/(\|-.*)\n(\|\w.*)$/m, '\1\2'))
end
# Now congeal the headers
while( text.gsub!(/(\{\|.*)\n(\|\w.*)$/m, '\1\2'))
end
# format the headers properly
while( text.gsub!(/(\{\|.*)\|([^_].*)$/, '\1|_. \2'))
end
# get rid of leading '{|'
text = text.gsub(/^\{\|(.*)$/) { |s| "table(stdtbl)\n#{$1}|" }
# get rid of leading '|-'
text = text.gsub(/^\|-(.*)$/, '\1|')
# get rid of trailing '|}'
text = text.gsub(/^\|\}.*$/, '')
# Internal Links
text = text.gsub(/\[\[Image:([^\s]+)\]\]/) { |s| "!#{$1}!" }
# Wiki page separator ':'
while( text.gsub!(/(\[\[\s*\w+):(\w+)/, '\1_\2') )
end
text
end
end
def prompt(text, options = {}, &block)
default = options[:default] || ''
while true
print "#{text} [#{default}]: "
value = STDIN.gets.chomp!
value = default if value.blank?
break if yield value
end
end
prompt('Target project identifier', :default => 'My Project') {|identifier| MMMigrate.target_project_identifier identifier}
prompt('Path to MoinMoin pages folder', :default => '/usr/local/moinwiki/data/pages') {|path| MMMigrate.target_moin_moin_path path}
MMMigrate.migrate
end
end