#!/usr/bin/env ruby require 'optparse' OPTIONS = { :instiki_root => nil, :storage => nil, } ARGV.options do |opts| script_name = File.basename($0) opts.banner = "Usage: ruby #{script_name} [options]" opts.separator "" opts.on("-t", "--storage /full/path/to/storage", String, "Full path to your storage, ", "such as /home/joe/instiki/storage/2500", "It should be the directory that ", "contains .snapshot files.") do |storage| OPTIONS[:storage] = storage end opts.separator "" opts.on("-i", "--instiki /full/path/to/instiki", String, "Full path to your Instiki installation, ", "such as /home/joe/instiki") do |instiki| OPTIONS[:instiki] = instiki end opts.separator "" opts.on("-o", "--outfile /full/path/to/output_file", String, "Full path (including filename!) to where ", "you want the SQL output placed, such as ", "/home/joe/instiki.sql") do |outfile| OPTIONS[:outfile] = outfile end opts.separator "" opts.on_tail("-h", "--help", "Show this help message.") { puts opts; exit } opts.parse! end if OPTIONS[:instiki].nil? or OPTIONS[:storage].nil? or OPTIONS[:outfile].nil? $stderr.puts "Please specify full paths to Instiki installation and storage," $stderr.puts "as well as the path to the output file" $stderr.puts puts ARGV.options exit -1 end if FileTest.exists? OPTIONS[:outfile] $stderr.puts "Output file #{OPTIONS[:outfile]} already exists!" $stderr.puts "Please specify a new file" $stderr.puts puts ARGV.options exit -1 end raise "Directory #{OPTIONS[:instiki]} not found" unless File.directory?(OPTIONS[:instiki]) raise "Directory #{OPTIONS[:storage]} not found" unless File.directory?(OPTIONS[:storage]) expected_page_rb_path = File.join(OPTIONS[:instiki], 'app/models/page.rb') raise "Instiki installation not found in #{OPTIONS[:instiki]}" unless File.file?(expected_page_rb_path) expected_snapshot_pattern = File.join(OPTIONS[:storage], '*.snapshot') raise "No snapshots found in OPTIONS[:storage]" if Dir[expected_snapshot_pattern].empty? INSTIKI_ROOT = File.expand_path(OPTIONS[:instiki]) ADDITIONAL_LOAD_PATHS = %w( app/models lib vendor/madeleine-0.7.1/lib vendor/RedCloth-3.0.3/lib vendor/rubyzip-0.5.8/lib ).map { |dir| "#{File.expand_path(File.join(INSTIKI_ROOT, dir))}" }.delete_if { |dir| not File.exist?(dir) } # Prepend to $LOAD_PATH ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } require 'webrick' require 'wiki_service' class Revision alias :__display_content :display_content def display_content return self end end def sql_insert(table, hash) output = "INSERT INTO #{table} (" output << hash.keys.join(", ") output << ") VALUES ('" output << hash.values.map{|v| v.to_s.gsub("'", "\\\\'")}.join("', '") output << "');" return output end WikiService.storage_path = OPTIONS[:storage] wiki = WikiService.instance File.open(OPTIONS[:outfile], 'w') { |outfile| wiki.webs.each_pair do |web_name, web| outfile.puts sql_insert(:webs, { :id => web.object_id, :name => web.name, :address => web.address, :password => web.password, :additional_style => web.additional_style, :allow_uploads => web.allow_uploads, :published => web.published, :count_pages => web.count_pages, :markup => web.markup, :color => web.color, :max_upload_size => web.max_upload_size, :safe_mode => web.safe_mode, :brackets_only => web.brackets_only, }) puts "Web #{web_name} has #{web.pages.keys.size} pages" web.pages.each_pair do |page_name, page| outfile.puts sql_insert(:pages, { :id => page.object_id, :web_id => web.object_id, :locked_by => page.locked_by, :name => page.name }) puts " Page #{page_name} has #{page.revisions.size} revisions" page.revisions.each_with_index do |rev, i| outfile.puts sql_insert(:revisions, { :id => rev.object_id, :page_id => page.object_id, :content => rev.content, :author => rev.author, :ip => '0.0.0.0', }) puts " Revision #{i} created at #{rev.created_at}" end end end ['webs', 'pages', 'revisions'].each do |table| outfile.puts "UPDATE #{table} SET created_at = NOW();" outfile.puts "UPDATE #{table} SET updated_at = NOW();" end outfile.puts "UPDATE revisions SET revised_at = NOW();" }