diff options
Diffstat (limited to 'activerecord/lib/active_record/tasks')
7 files changed, 100 insertions, 181 deletions
diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb index 36133bab4c..afd493011e 100644 --- a/activerecord/lib/active_record/tasks/database_tasks.rb +++ b/activerecord/lib/active_record/tasks/database_tasks.rb @@ -3,10 +3,41 @@ module ActiveRecord class DatabaseAlreadyExists < StandardError; end # :nodoc: class DatabaseNotSupported < StandardError; end # :nodoc: - module DatabaseTasks # :nodoc: + # <tt>ActiveRecord::Tasks::DatabaseTasks</tt> is a utility class, which encapsulates + # logic behind common tasks used to manage database and migrations. + # + # The tasks defined here are used in rake tasks provided by Active Record. + # + # In order to use DatabaseTasks, a few config values need to be set. All the needed + # config values are set by Rails already, so it's necessary to do it only if you + # want to change the defaults or when you want to use Active Record outside of Rails + # (in such case after configuring the database tasks, you can also use the rake tasks + # defined in Active Record). + # + # + # 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. + # + # Example usage of +DatabaseTasks+ outside Rails could look as such: + # + # include ActiveRecord::Tasks + # DatabaseTasks.database_configuration = YAML.load(File.read('my_database_config.yml')) + # DatabaseTasks.db_dir = 'db' + # # other settings... + # + # DatabaseTasks.create_current('production') + module DatabaseTasks extend self - attr_writer :current_config + attr_writer :current_config, :db_dir, :migrations_paths, :fixtures_path, :root, :env, :seed_loader + attr_accessor :database_configuration LOCAL_HOSTS = ['127.0.0.1', 'localhost'] @@ -19,20 +50,36 @@ module ActiveRecord register_task(/postgresql/, ActiveRecord::Tasks::PostgreSQLDatabaseTasks) register_task(/sqlite/, ActiveRecord::Tasks::SQLiteDatabaseTasks) - register_task(/firebird/, ActiveRecord::Tasks::FirebirdDatabaseTasks) - register_task(/sqlserver/, ActiveRecord::Tasks::SqlserverDatabaseTasks) - register_task(/(oci|oracle)/, ActiveRecord::Tasks::OracleDatabaseTasks) + def db_dir + @db_dir ||= Rails.application.config.paths["db"].first + end + + def migrations_paths + @migrations_paths ||= Rails.application.paths['db/migrate'].to_a + end + + def fixtures_path + @fixtures_path ||= File.join(root, 'test', 'fixtures') + end + + def root + @root ||= Rails.root + end + + def env + @env ||= Rails.env + end + + def seed_loader + @seed_loader ||= Rails.application + end def current_config(options = {}) - options.reverse_merge! :env => Rails.env + options.reverse_merge! :env => env if options.has_key?(:config) @current_config = options[:config] else - @current_config ||= if ENV['DATABASE_URL'] - database_url_config - else - ActiveRecord::Base.configurations[options[:env]] - end + @current_config ||= ActiveRecord::Base.configurations[options[:env]] end end @@ -50,15 +97,11 @@ module ActiveRecord each_local_configuration { |configuration| create configuration } end - def create_current(environment = Rails.env) + def create_current(environment = env) each_current_configuration(environment) { |configuration| create configuration } - ActiveRecord::Base.establish_connection environment - end - - def create_database_url - create database_url_config + ActiveRecord::Base.establish_connection(environment.to_sym) end def drop(*arguments) @@ -73,17 +116,13 @@ module ActiveRecord each_local_configuration { |configuration| drop configuration } end - def drop_current(environment = Rails.env) + def drop_current(environment = env) each_current_configuration(environment) { |configuration| drop configuration } end - def drop_database_url - drop database_url_config - end - - def charset_current(environment = Rails.env) + def charset_current(environment = env) charset ActiveRecord::Base.configurations[environment] end @@ -92,7 +131,7 @@ module ActiveRecord class_for_adapter(configuration['adapter']).new(*arguments).charset end - def collation_current(environment = Rails.env) + def collation_current(environment = env) collation ActiveRecord::Base.configurations[environment] end @@ -117,13 +156,41 @@ module ActiveRecord class_for_adapter(configuration['adapter']).new(*arguments).structure_load(filename) end - private + def load_schema(format = ActiveRecord::Base.schema_format, file = nil) + case format + when :ruby + file ||= File.join(db_dir, "schema.rb") + check_schema_file(file) + load(file) + when :sql + file ||= File.join(db_dir, "structure.sql") + check_schema_file(file) + structure_load(current_config, file) + else + raise ArgumentError, "unknown format #{format.inspect}" + end + end - def database_url_config - @database_url_config ||= - ConnectionAdapters::ConnectionSpecification::Resolver.new(ENV["DATABASE_URL"], {}).spec.config.stringify_keys + 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.} + message << %{ If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded.} if defined?(::Rails) + Kernel.abort message + end end + def load_seed + if seed_loader + seed_loader.load_seed + else + raise "You tried to load seed data, but no seed loader is specified. Please specify seed " + + "loader with ActiveRecord::Tasks::DatabaseTasks.seed_loader = your_seed_loader\n" + + "Seed loader should respond to load_seed method" + end + end + + private + def class_for_adapter(adapter) key = @tasks.keys.detect { |pattern| adapter[pattern] } unless key @@ -134,7 +201,7 @@ module ActiveRecord def each_current_configuration(environment) environments = [environment] - environments << 'test' if environment.development? + environments << 'test' if environment == 'development' configurations = ActiveRecord::Base.configurations.values_at(*environments) configurations.compact.each do |configuration| diff --git a/activerecord/lib/active_record/tasks/firebird_database_tasks.rb b/activerecord/lib/active_record/tasks/firebird_database_tasks.rb deleted file mode 100644 index 98014a38ea..0000000000 --- a/activerecord/lib/active_record/tasks/firebird_database_tasks.rb +++ /dev/null @@ -1,56 +0,0 @@ -module ActiveRecord - module Tasks # :nodoc: - class FirebirdDatabaseTasks # :nodoc: - delegate :connection, :establish_connection, to: ActiveRecord::Base - - def initialize(configuration) - ActiveSupport::Deprecation.warn "This database tasks were deprecated, because this tasks should be served by the 3rd party adapter." - @configuration = configuration - end - - def create - $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' - end - - def drop - $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' - end - - def purge - establish_connection(:test) - connection.recreate_database! - end - - def charset - $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' - end - - def structure_dump(filename) - set_firebird_env(configuration) - db_string = firebird_db_string(configuration) - Kernel.system "isql -a #{db_string} > #{filename}" - end - - def structure_load(filename) - set_firebird_env(configuration) - db_string = firebird_db_string(configuration) - Kernel.system "isql -i #{filename} #{db_string}" - end - - private - - def set_firebird_env(config) - ENV['ISC_USER'] = config['username'].to_s if config['username'] - ENV['ISC_PASSWORD'] = config['password'].to_s if config['password'] - end - - def firebird_db_string(config) - FireRuby::Database.db_string_for(config.symbolize_keys) - end - - def configuration - @configuration - end - end - end -end diff --git a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb index 50569d2462..c755831e6d 100644 --- a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb @@ -134,8 +134,9 @@ IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION; 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 ]) if v + args.concat([ "--#{k}", v.to_s ]) if v end + args end end diff --git a/activerecord/lib/active_record/tasks/oracle_database_tasks.rb b/activerecord/lib/active_record/tasks/oracle_database_tasks.rb deleted file mode 100644 index de3aa50e5e..0000000000 --- a/activerecord/lib/active_record/tasks/oracle_database_tasks.rb +++ /dev/null @@ -1,45 +0,0 @@ -module ActiveRecord - module Tasks # :nodoc: - class OracleDatabaseTasks # :nodoc: - delegate :connection, :establish_connection, to: ActiveRecord::Base - - def initialize(configuration) - ActiveSupport::Deprecation.warn "This database tasks were deprecated, because this tasks should be served by the 3rd party adapter." - @configuration = configuration - end - - def create - $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' - end - - def drop - $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' - end - - def purge - establish_connection(:test) - connection.structure_drop.split(";\n\n").each { |ddl| connection.execute(ddl) } - end - - def charset - $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' - end - - def structure_dump(filename) - establish_connection(configuration) - File.open(filename, "w:utf-8") { |f| f << connection.structure_dump } - end - - def structure_load(filename) - establish_connection(configuration) - IO.read(filename).split(";\n\n").each { |ddl| connection.execute(ddl) } - end - - private - - def configuration - @configuration - 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 0b1b030516..3d02ee07d0 100644 --- a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb @@ -59,7 +59,7 @@ module ActiveRecord def structure_load(filename) set_psql_env - Kernel.system("psql -f #{filename} #{configuration['database']}") + Kernel.system("psql -q -f #{Shellwords.escape(filename)} #{configuration['database']}") end private diff --git a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb index de8b16627e..5688931db2 100644 --- a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb @@ -3,7 +3,7 @@ module ActiveRecord class SQLiteDatabaseTasks # :nodoc: delegate :connection, :establish_connection, to: ActiveRecord::Base - def initialize(configuration, root = Rails.root) + def initialize(configuration, root = ActiveRecord::Tasks::DatabaseTasks.root) @configuration, @root = configuration, root end diff --git a/activerecord/lib/active_record/tasks/sqlserver_database_tasks.rb b/activerecord/lib/active_record/tasks/sqlserver_database_tasks.rb deleted file mode 100644 index c718ee03a8..0000000000 --- a/activerecord/lib/active_record/tasks/sqlserver_database_tasks.rb +++ /dev/null @@ -1,48 +0,0 @@ -require 'shellwords' - -module ActiveRecord - module Tasks # :nodoc: - class SqlserverDatabaseTasks # :nodoc: - delegate :connection, :establish_connection, to: ActiveRecord::Base - - def initialize(configuration) - ActiveSupport::Deprecation.warn "This database tasks were deprecated, because this tasks should be served by the 3rd party adapter." - @configuration = configuration - end - - def create - $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' - end - - def drop - $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' - end - - def purge - test = configuration.deep_dup - test_database = test['database'] - test['database'] = 'master' - establish_connection(test) - connection.recreate_database!(test_database) - end - - def charset - $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' - end - - def structure_dump(filename) - Kernel.system("smoscript -s #{configuration['host']} -d #{configuration['database']} -u #{configuration['username']} -p #{configuration['password']} -f #{filename} -A -U") - end - - def structure_load(filename) - Kernel.system("sqlcmd -S #{configuration['host']} -d #{configuration['database']} -U #{configuration['username']} -P #{configuration['password']} -i #{filename}") - end - - private - - def configuration - @configuration - end - end - end -end |