Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@wuputah
Created October 17, 2008 08:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wuputah/17372 to your computer and use it in GitHub Desktop.
Save wuputah/17372 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
require 'rubygems'
require 'mysql'
require 'highline'
require 'optparse'
class CopyDatabase
def initialize(options = {})
@connection = Mysql.connect(options[:host], options[:username], options[:password])
@connection.query_with_result = false
@options = options
Kernel.at_exit { @connection.close }
end
def copy(from_database, to_database)
@from_database, @to_database, @tables = [from_database, to_database, nil]
@connection.select_db(from_database)
return if tables.empty?
drop_database if @options[:drop_database]
create_database if @options[:create_database]
copy_structure
lock_tables { copy_data }
end
private
def create_database
query('CREATE DATABASE ' + "`#{@to_database}`")
end
def drop_database
query('DROP DATABASE IF EXISTS ' + "`#{@to_database}`")
end
def copy_structure
tables.each do |table|
query('DROP TABLE IF EXISTS ' + sanitized_table(@to_database, table))
query('CREATE TABLE ' + sanitized_table(@to_database, table) +
' LIKE ' + sanitized_table(@from_database, table))
end
end
def copy_data
tables.each do |table|
disable_keys(@to_database, table) do
query('INSERT INTO ' + sanitized_table(@to_database, table) +
' SELECT * FROM ' + sanitized_table(@from_database, table))
end
end
end
def disable_keys(database, table)
query('ALTER TABLE ' + sanitized_table(database, table) + ' DISABLE KEYS')
yield
query('ALTER TABLE ' + sanitized_table(database, table) + ' ENABLE KEYS')
end
def lock_tables
query('LOCK TABLES ' + locks.join(', '))
yield
query('UNLOCK TABLES')
end
def locks
tables.inject(Array.new) do |arr, table|
arr << (sanitized_table(@to_database, table) + ' WRITE') <<
(sanitized_table(@from_database, table) + ' READ')
end
end
def tables
@tables ||= @connection.list_tables
end
def sanitized_table(database, table)
"`#{database}`.`#{table}`"
end
def query(sql)
puts sql if @options[:verbose]
@connection.query(sql)
end
end
class CopyDatabaseController
def self.run(args)
new(args).run
end
def initialize(args)
@ui = HighLine.new
parse(args)
end
def run
CopyDatabase.new(@options).
copy(@from_database, @to_database)
end
private
def parse(args)
@options = {
:user => ENV['USER'],
:password => '',
:verbose => false,
:host => '127.0.0.1',
:create_database => false,
:drop_database => false
}
parser = OptionParser.new do |opts|
opts.banner = "Usage: #{File.basename($0)} [options] from-database to-database"
opts.on('-u', '--user',
'User to use when connecting to MySQL.',
"Default: #{@options[:user]}") do |value|
@options[:user] = value
end
opts.on('-p', '--password',
'Prompt for a password to use when connecting to MySQL.') do
@options[:password] = @ui.ask('Enter password: ') { |q| q.echo = false }
end
opts.on('-h', '--host HOST',
'Host or socket to connect to.',
"Default: #{@options[:host]}") do |value|
@options[:host] = value
end
opts.on('-v', '--verbose', 'Prints queries as they are executed.') do
@options[:verbose] = true
end
opts.on('-C', '--create-database',
'Create the destination database before copying.') do
@options[:create_database] = true
end
opts.on('-f', '--force',
'Drop and then create the destination database before copying.') do
@options[:drop_database] = true
@options[:create_database] = true
end
opts.on('--help', 'Display this help message.') do
puts opts
exit
end
end
parser.parse!(args)
if args.size != 2
puts parser
exit
end
@from_database, @to_database = args
end
end
CopyDatabaseController.run(ARGV)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment