| 43 |
43 |
'low' => priorities[0],
|
| 44 |
44 |
'normal' => priorities[1],
|
| 45 |
45 |
'high' => priorities[2],
|
| 46 |
|
'highest' => priorities[3]
|
|
46 |
'highest' => priorities[3],
|
|
47 |
# ---
|
|
48 |
'trivial' => priorities[0],
|
|
49 |
'minor' => priorities[1],
|
|
50 |
'major' => priorities[2],
|
|
51 |
'critical' => priorities[3],
|
|
52 |
'blocker' => priorities[4]
|
| 47 |
53 |
}
|
| 48 |
54 |
|
| 49 |
55 |
TRACKER_BUG = Tracker.find_by_position(1)
|
| ... | ... | |
| 144 |
150 |
end
|
| 145 |
151 |
|
| 146 |
152 |
class TracWikiPage < ActiveRecord::Base
|
| 147 |
|
set_table_name :wiki
|
|
153 |
set_table_name :wiki
|
|
154 |
set_primary_key :name
|
| 148 |
155 |
|
|
156 |
has_many :attachments, :class_name => "TracAttachment", :foreign_key => :id, :conditions => "#{TracMigrate::TracAttachment.table_name}.type = 'wiki'"
|
|
157 |
|
|
158 |
def time; Time.at(read_attribute(:time)) end
|
|
159 |
|
| 149 |
160 |
def self.columns
|
| 150 |
161 |
# Hides readonly Trac field to prevent clash with AR readonly? method (Rails 2.0)
|
| 151 |
162 |
super.select {|column| column.name.to_s != 'readonly'}
|
| ... | ... | |
| 190 |
201 |
# Basic wiki syntax conversion
|
| 191 |
202 |
def self.convert_wiki_text(text)
|
| 192 |
203 |
# Titles
|
| 193 |
|
text = text.gsub(/^(\=+)\s(.+)\s(\=+)/) {|s| "\nh#{$1.length}. #{$2}\n"}
|
|
204 |
text = text.gsub(/^(\=+)\s(.+?)\s(\=+)/) {|s| "\nh#{$1.length}. #{$2}\n"}
|
| 194 |
205 |
# External Links
|
| 195 |
206 |
text = text.gsub(/\[(http[^\s]+)\s+([^\]]+)\]/) {|s| "\"#{$2}\":#{$1}"}
|
| 196 |
207 |
# Internal Links
|
| 197 |
208 |
text = text.gsub(/\[\[BR\]\]/, "\n") # This has to go before the rules below
|
| 198 |
|
text = text.gsub(/\[\"(.+)\".*\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
|
| 199 |
|
text = text.gsub(/\[wiki:\"(.+)\".*\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
|
| 200 |
|
text = text.gsub(/\[wiki:\"(.+)\".*\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
|
| 201 |
|
text = text.gsub(/\[wiki:([^\s\]]+).*\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
|
|
209 |
text = text.gsub(/\[\[PageOutline\(?.*\)?\]\]/, "{{>toc}}\n")
|
|
210 |
# * Images
|
|
211 |
text = text.gsub(/\[\[Image\((.+?)\)\]\]/) {|s| "!#{$1}!"}
|
|
212 |
# * Wiki links
|
|
213 |
text = text.gsub(/\[wiki:\"(.+?)\".*?\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
|
|
214 |
text = text.gsub(/\[wiki:([^ ]+?)\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
|
|
215 |
text = text.gsub(/\[wiki:(.+?) (.+?)\]/) {|s| "[[#{$1.delete(',./?;|:')}|#{$2}]]"}
|
|
216 |
# * CamelCase links
|
|
217 |
text = text.gsub(/\[([A-Z][a-z]+[A-Z][a-z]+[A-Za-z]*) (.+?)\]/) {|s| "[[#{$1}|#{$2}]]"}
|
|
218 |
text = text.gsub(/(\s)([A-Z][a-z]+[A-Z][a-z]+[A-Za-z]*)/) {|s| "#{$1}[[#{$2}]]"}
|
|
219 |
# * Attachments
|
|
220 |
text = text.gsub(/\[attachment:\"(.+?)\"(.*?)\]/) {|s| "attachment:#{$1.delete(',?;|:')} #{$2}"}
|
| 202 |
221 |
# Revisions links
|
| 203 |
222 |
text = text.gsub(/\[(\d+)\]/, 'r\1')
|
|
223 |
# Remaining External Links
|
|
224 |
text = text.gsub(/([^\[])\[(.+?) (.+?)\]/) {|s| "#{$1}\"#{$3}\":#{$2}"}
|
| 204 |
225 |
# Ticket number re-writing
|
| 205 |
226 |
text = text.gsub(/#(\d+)/) do |s|
|
| 206 |
227 |
TICKET_MAP[$1.to_i] ||= $1
|
| ... | ... | |
| 224 |
245 |
text
|
| 225 |
246 |
end
|
| 226 |
247 |
|
|
248 |
TRAC_WIKI_PAGES = %w(TracAccessibility TracAdmin TracBackup TracBrowser TracCgi TracChangeset TracEnvironment TracFastCgi TracGuide TracImport TracIni TracInstall TracInterfaceCustomization TracLinks TracLogging TracModPython TracNotification TracPermissions TracPlugins TracQuery TracReports TracRoadmap TracRss TracSearch TracStandalone TracSupport TracSyntaxColoring TracTickets TracTicketsCustomFields TracTimeline TracUnicode TracUpgrade TracWiki WikiDeletePage WikiFormatting WikiHtml WikiMacros WikiNewPage WikiPageNames WikiProcessors WikiRestructuredText WikiRestructuredTextLinks CamelCase TitleIndex)
|
|
249 |
|
| 227 |
250 |
def self.migrate
|
| 228 |
251 |
establish_connection
|
| 229 |
252 |
|
| ... | ... | |
| 236 |
259 |
migrated_custom_values = 0
|
| 237 |
260 |
migrated_ticket_attachments = 0
|
| 238 |
261 |
migrated_wiki_edits = 0
|
|
262 |
migrated_wiki_attachments = 0
|
| 239 |
263 |
|
| 240 |
264 |
# Components
|
| 241 |
265 |
print "Migrating components"
|
| ... | ... | |
| 388 |
412 |
TracWikiPage.find(:all, :order => 'name, version').each do |page|
|
| 389 |
413 |
print '.'
|
| 390 |
414 |
STDOUT.flush
|
|
415 |
next if TRAC_WIKI_PAGES.include?(page.name)
|
| 391 |
416 |
p = wiki.find_or_new_page(page.name)
|
| 392 |
417 |
p.content = WikiContent.new(:page => p) if p.new_record?
|
| 393 |
418 |
p.content.text = page.text
|
| ... | ... | |
| 395 |
420 |
p.content.comments = page.comment
|
| 396 |
421 |
p.new_record? ? p.save : p.content.save
|
| 397 |
422 |
migrated_wiki_edits += 1 unless p.content.new_record?
|
|
423 |
|
|
424 |
# Attachments
|
|
425 |
page.attachments.each do |attachment|
|
|
426 |
next unless attachment.exist?
|
|
427 |
next if p.attachments.find_by_filename(attachment.filename.gsub(/^.*(\\|\/)/, '').gsub(/[^\w\.\-]/,'_')) #add only once per page
|
|
428 |
a = Attachment.new :created_on => attachment.time
|
|
429 |
a.file = attachment
|
|
430 |
a.author = find_or_create_user(attachment.author)
|
|
431 |
a.container = p
|
|
432 |
migrated_wiki_attachments += 1 if a.save
|
|
433 |
end
|
| 398 |
434 |
end
|
| 399 |
435 |
|
| 400 |
436 |
wiki.reload
|
| ... | ... | |
| 409 |
445 |
puts "Components: #{migrated_components}/#{TracComponent.count}"
|
| 410 |
446 |
puts "Milestones: #{migrated_milestones}/#{TracMilestone.count}"
|
| 411 |
447 |
puts "Tickets: #{migrated_tickets}/#{TracTicket.count}"
|
| 412 |
|
puts "Ticket files: #{migrated_ticket_attachments}/" + TracAttachment.count("type = 'ticket'").to_s
|
|
448 |
puts "Ticket files: #{migrated_ticket_attachments}/" + TracAttachment.count(:conditions => "type = 'ticket'").to_s
|
| 413 |
449 |
puts "Custom values: #{migrated_custom_values}/#{TracTicketCustom.count}"
|
| 414 |
450 |
puts "Wiki edits: #{migrated_wiki_edits}/#{TracWikiPage.count}"
|
|
451 |
puts "Wiki files: #{migrated_wiki_attachments}/" + TracAttachment.count(:conditions => "type = 'wiki'").to_s
|
| 415 |
452 |
end
|
| 416 |
453 |
|
| 417 |
454 |
def self.limit_for(klass, attribute)
|