diff options
Diffstat (limited to 'activerecord/lib/active_record/tasks')
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 |