aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/tasks
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/tasks')
-rw-r--r--activerecord/lib/active_record/tasks/database_tasks.rb72
-rw-r--r--activerecord/lib/active_record/tasks/mysql_database_tasks.rb49
-rw-r--r--activerecord/lib/active_record/tasks/postgresql_database_tasks.rb40
-rw-r--r--activerecord/lib/active_record/tasks/sqlite_database_tasks.rb12
4 files changed, 130 insertions, 43 deletions
diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb
index b7315ed4b3..c0c29a618c 100644
--- a/activerecord/lib/active_record/tasks/database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/database_tasks.rb
@@ -1,9 +1,11 @@
+require 'active_support/core_ext/string/filters'
+
module ActiveRecord
module Tasks # :nodoc:
class DatabaseAlreadyExists < StandardError; end # :nodoc:
class DatabaseNotSupported < StandardError; end # :nodoc:
- # <tt>ActiveRecord::Tasks::DatabaseTasks</tt> is a utility class, which encapsulates
+ # ActiveRecord::Tasks::DatabaseTasks is a utility class, which encapsulates
# logic behind common tasks used to manage database and migrations.
#
# The tasks defined here are used with Rake tasks provided by Active Record.
@@ -16,15 +18,15 @@ module ActiveRecord
#
# The possible config values are:
#
- # * +env+: current environment (like Rails.env).
- # * +database_configuration+: configuration of your databases (as in +config/database.yml+).
- # * +db_dir+: your +db+ directory.
- # * +fixtures_path+: a path to fixtures directory.
- # * +migrations_paths+: a list of paths to directories with migrations.
- # * +seed_loader+: an object which will load seeds, it needs to respond to the +load_seed+ method.
- # * +root+: a path to the root of the application.
+ # * +env+: current environment (like Rails.env).
+ # * +database_configuration+: configuration of your databases (as in +config/database.yml+).
+ # * +db_dir+: your +db+ directory.
+ # * +fixtures_path+: a path to fixtures directory.
+ # * +migrations_paths+: a list of paths to directories with migrations.
+ # * +seed_loader+: an object which will load seeds, it needs to respond to the +load_seed+ method.
+ # * +root+: a path to the root of the application.
#
- # Example usage of +DatabaseTasks+ outside Rails could look as such:
+ # Example usage of DatabaseTasks outside Rails could look as such:
#
# include ActiveRecord::Tasks
# DatabaseTasks.database_configuration = YAML.load_file('my_database_config.yml')
@@ -92,8 +94,9 @@ module ActiveRecord
rescue DatabaseAlreadyExists
$stderr.puts "#{configuration['database']} already exists"
rescue Exception => error
- $stderr.puts error, *(error.backtrace)
+ $stderr.puts error
$stderr.puts "Couldn't create database for #{configuration.inspect}"
+ raise
end
def create_all
@@ -113,8 +116,9 @@ module ActiveRecord
rescue ActiveRecord::NoDatabaseError
$stderr.puts "Database '#{configuration['database']}' does not exist"
rescue Exception => error
- $stderr.puts error, *(error.backtrace)
+ $stderr.puts error
$stderr.puts "Couldn't drop #{configuration['database']}"
+ raise
end
def drop_all
@@ -127,6 +131,18 @@ module ActiveRecord
}
end
+ def migrate
+ verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
+ version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
+ scope = ENV['SCOPE']
+ verbose_was, Migration.verbose = Migration.verbose, verbose
+ Migrator.migrate(migrations_paths, version) do |migration|
+ scope.blank? || scope == migration.scope
+ end
+ ensure
+ Migration.verbose = verbose_was
+ end
+
def charset_current(environment = env)
charset ActiveRecord::Base.configurations[environment]
end
@@ -159,6 +175,7 @@ module ActiveRecord
each_current_configuration(environment) { |configuration|
purge configuration
}
+ ActiveRecord::Base.establish_connection(environment.to_sym)
end
def structure_dump(*arguments)
@@ -173,21 +190,46 @@ module ActiveRecord
class_for_adapter(configuration['adapter']).new(*arguments).structure_load(filename)
end
- def load_schema(format = ActiveRecord::Base.schema_format, file = nil)
+ def load_schema(configuration, format = ActiveRecord::Base.schema_format, file = nil) # :nodoc:
+ file ||= schema_file(format)
+
case format
when :ruby
- file ||= File.join(db_dir, "schema.rb")
check_schema_file(file)
+ ActiveRecord::Base.establish_connection(configuration)
load(file)
when :sql
- file ||= File.join(db_dir, "structure.sql")
check_schema_file(file)
- structure_load(current_config, file)
+ structure_load(configuration, file)
else
raise ArgumentError, "unknown format #{format.inspect}"
end
end
+ def load_schema_for(*args)
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ This method was renamed to `#load_schema` and will be removed in the future.
+ Use `#load_schema` instead.
+ MSG
+ load_schema(*args)
+ end
+
+ def schema_file(format = ActiveRecord::Base.schema_format)
+ case format
+ when :ruby
+ File.join(db_dir, "schema.rb")
+ when :sql
+ File.join(db_dir, "structure.sql")
+ end
+ end
+
+ def load_schema_current(format = ActiveRecord::Base.schema_format, file = nil, environment = env)
+ each_current_configuration(environment) { |configuration|
+ load_schema configuration, format, file
+ }
+ ActiveRecord::Base.establish_connection(environment.to_sym)
+ end
+
def check_schema_file(filename)
unless File.exist?(filename)
message = %{#{filename} doesn't exist yet. Run `rake db:migrate` to create it, then try again.}
diff --git a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
index d890196f47..8929aa85c8 100644
--- a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
@@ -23,7 +23,7 @@ module ActiveRecord
end
rescue error_class => error
if error.respond_to?(:errno) && error.errno == ACCESS_DENIED_ERROR
- $stdout.print error.error
+ $stdout.print error.message
establish_connection root_configuration_without_database
connection.create_database configuration['database'], creation_options
if configuration['username'] != 'root'
@@ -31,6 +31,7 @@ module ActiveRecord
end
establish_connection configuration
else
+ $stderr.puts error.inspect
$stderr.puts "Couldn't create database for #{configuration.inspect}, #{creation_options.inspect}"
$stderr.puts "(If you set the charset manually, make sure you have a matching collation)" if configuration['encoding']
end
@@ -55,21 +56,21 @@ module ActiveRecord
end
def structure_dump(filename)
- args = prepare_command_options('mysqldump')
+ args = prepare_command_options
args.concat(["--result-file", "#{filename}"])
args.concat(["--no-data"])
+ args.concat(["--routines"])
args.concat(["#{configuration['database']}"])
- unless Kernel.system(*args)
- $stderr.puts "Could not dump the database structure. "\
- "Make sure `mysqldump` is in your PATH and check the command output for warnings."
- end
+
+ run_cmd('mysqldump', args, 'dumping')
end
def structure_load(filename)
- args = prepare_command_options('mysql')
+ args = prepare_command_options
args.concat(['--execute', %{SET FOREIGN_KEY_CHECKS = 0; SOURCE #{filename}; SET FOREIGN_KEY_CHECKS = 1}])
args.concat(["--database", "#{configuration['database']}"])
- Kernel.system(*args)
+
+ run_cmd('mysql', args, 'loading')
end
private
@@ -128,17 +129,33 @@ IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION;
$stdin.gets.strip
end
- def prepare_command_options(command)
- args = [command]
- args.concat(['--user', configuration['username']]) if configuration['username']
- args << "--password=#{configuration['password']}" if configuration['password']
- args.concat(['--default-character-set', configuration['encoding']]) if configuration['encoding']
- configuration.slice('host', 'port', 'socket').each do |k, v|
- args.concat([ "--#{k}", v.to_s ]) if v
- end
+ def prepare_command_options
+ args = {
+ 'host' => '--host',
+ 'port' => '--port',
+ 'socket' => '--socket',
+ 'username' => '--user',
+ 'password' => '--password',
+ 'encoding' => '--default-character-set',
+ 'sslca' => '--ssl-ca',
+ 'sslcert' => '--ssl-cert',
+ 'sslcapath' => '--ssl-capath',
+ 'sslcipher' => '--ssh-cipher',
+ 'sslkey' => '--ssl-key'
+ }.map { |opt, arg| "#{arg}=#{configuration[opt]}" if configuration[opt] }.compact
args
end
+
+ def run_cmd(cmd, args, action)
+ fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
+ end
+
+ def run_cmd_error(cmd, args, action)
+ msg = "failed to execute: `#{cmd}`\n"
+ msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
+ msg
+ end
end
end
end
diff --git a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
index 3d02ee07d0..cd7d949239 100644
--- a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
@@ -1,5 +1,3 @@
-require 'shellwords'
-
module ActiveRecord
module Tasks # :nodoc:
class PostgreSQLDatabaseTasks # :nodoc:
@@ -46,20 +44,31 @@ module ActiveRecord
def structure_dump(filename)
set_psql_env
- search_path = configuration['schema_search_path']
- unless search_path.blank?
- search_path = search_path.split(",").map{|search_path_part| "--schema=#{Shellwords.escape(search_path_part.strip)}" }.join(" ")
- end
- command = "pg_dump -i -s -x -O -f #{Shellwords.escape(filename)} #{search_path} #{Shellwords.escape(configuration['database'])}"
- raise 'Error dumping database' unless Kernel.system(command)
+ search_path = case ActiveRecord::Base.dump_schemas
+ when :schema_search_path
+ configuration['schema_search_path']
+ when :all
+ nil
+ when String
+ ActiveRecord::Base.dump_schemas
+ end
- File.open(filename, "a") { |f| f << "SET search_path TO #{ActiveRecord::Base.connection.schema_search_path};\n\n" }
+ args = ['-s', '-x', '-O', '-f', filename]
+ unless search_path.blank?
+ args << search_path.split(',').map do |part|
+ "--schema=#{part.strip}"
+ end.join(' ')
+ end
+ args << configuration['database']
+ run_cmd('pg_dump', args, 'dumping')
+ File.open(filename, "a") { |f| f << "SET search_path TO #{connection.schema_search_path};\n\n" }
end
def structure_load(filename)
set_psql_env
- Kernel.system("psql -q -f #{Shellwords.escape(filename)} #{configuration['database']}")
+ args = [ '-q', '-f', filename, configuration['database'] ]
+ run_cmd('psql', args, 'loading' )
end
private
@@ -85,6 +94,17 @@ module ActiveRecord
ENV['PGPASSWORD'] = configuration['password'].to_s if configuration['password']
ENV['PGUSER'] = configuration['username'].to_s if configuration['username']
end
+
+ def run_cmd(cmd, args, action)
+ fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
+ end
+
+ def run_cmd_error(cmd, args, action)
+ msg = "failed to execute:\n"
+ msg << "#{cmd} #{args.join(' ')}\n\n"
+ msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
+ msg
+ end
end
end
end
diff --git a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
index 5688931db2..9ec3c8a94a 100644
--- a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
@@ -19,9 +19,17 @@ module ActiveRecord
path = Pathname.new configuration['database']
file = path.absolute? ? path.to_s : File.join(root, path)
- FileUtils.rm(file) if File.exist?(file)
+ FileUtils.rm(file)
+ rescue Errno::ENOENT => error
+ raise NoDatabaseError.new(error.message, error)
+ end
+
+ def purge
+ drop
+ rescue NoDatabaseError
+ ensure
+ create
end
- alias :purge :drop
def charset
connection.encoding