require 'tempfile' require 'fileutils'

desc 'Attempts to convert db/structure.sql into db/000_create_initial_schema.rb.' task :structure_sql_to_migration do

drop_body = []
structure_file = File.join('db','structure.sql')
migration_file = File.join('db','migrate/000_create_initial_schema.rb')
File.delete(migration_file) if File.exists?(migration_file)
temp_file = Tempfile.new('000_create_initial_schema.rb')
begin
  File.open(structure_file, 'r') do |file|
    header = <<-eos1

class CreateInitialSchema < ActiveRecord::Migration

def up
  statements = <<-eos

eos1

temp_file.puts header
ignore_next_line = false
file.each_line do |line|
  unless line.strip == '' || line.starts_with?("--")
    if line.starts_with?("INSERT INTO schema_migrations ") || line.starts_with?("CREATE TABLE schema_migrations") || line.starts_with?("CREATE UNIQUE INDEX unique_schema_migrations") 
      ignore_next_line = true
    end

    if ignore_next_line
      puts "ignoring: #{line}"
    else
      puts "   using: #{line}"
      # remove space from end of line and non-unix line-terminators so we can expect ";\n" at the real end of a function, for example
      temp_file.puts "#{line.rstrip}\n"
      if line.starts_with?("CREATE FUNCTION ")
        step1 = line.split(/[\(\)]/).collect{|t| t.strip==t ? t : t.split(' ')}.flatten
        function_name_with_args = "#{step1[0].split.last}(#{step1[1]})"
        drop_body << "DROP FUNCTION #{function_name_with_args} CASCADE;"
      elsif line.starts_with?("CREATE SEQUENCE ")
        name = (line.split)[2]
        if name.starts_with?('"')
          name = (line.split(/"/).collect{|t| t.strip==t ? t : t.split(' ')}.flatten)[2]
        end
        drop_body << "DROP SEQUENCE #{name} CASCADE;"
      elsif line.starts_with?("CREATE TABLE ")
        name = (line.split)[2]
        if name.starts_with?('"')
          name = (line.split(/"/).collect{|t| t.strip==t ? t : t.split(' ')}.flatten)[2]
        end
        drop_body << "DROP TABLE #{name} CASCADE;"
      end
    end

    ignore_next_line = false if line[';']
  end
end
middle = <<-eos1

eos

  statements.split(";\n").each {|s| execute s}
end

def down
  statements = <<-eos

eos1

temp_file.puts middle
drop_body.reverse.each {|s|temp_file.puts s}
footer = <<-eos1

eos

  statements.split(";\n").each {|s| execute s}
end

end eos1

    temp_file.puts footer
  end
  temp_file.rewind
  FileUtils.mv(temp_file.path, migration_file)
ensure
  temp_file.close
  temp_file.unlink
end

end