diff options
Diffstat (limited to 'activerecord/lib/active_record/railties/databases.rake')
-rw-r--r-- | activerecord/lib/active_record/railties/databases.rake | 255 |
1 files changed, 100 insertions, 155 deletions
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 259d0ff12b..04c2be045d 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -2,14 +2,8 @@ require 'active_record' db_namespace = namespace :db do task :load_config do - ActiveRecord::Base.configurations = Rails.application.config.database_configuration - ActiveRecord::Migrator.migrations_paths = Rails.application.paths['db/migrate'].to_a - - if defined?(ENGINE_PATH) && engine = Rails::Engine.find(ENGINE_PATH) - if engine.paths['db/migrate'].existent - ActiveRecord::Migrator.migrations_paths += engine.paths['db/migrate'].to_a - end - end + ActiveRecord::Base.configurations = ActiveRecord::Tasks::DatabaseTasks.database_configuration || {} + ActiveRecord::Migrator.migrations_paths = ActiveRecord::Tasks::DatabaseTasks.migrations_paths end namespace :create do @@ -18,13 +12,9 @@ db_namespace = namespace :db do end end - desc 'Create the database from DATABASE_URL or config/database.yml for the current Rails.env (use db:create:all to create all dbs in the config)' + desc 'Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to create all databases in the config). Without RAILS_ENV it defaults to creating the development and test databases.' task :create => [:load_config] do - if ENV['DATABASE_URL'] - ActiveRecord::Tasks::DatabaseTasks.create_database_url - else - ActiveRecord::Tasks::DatabaseTasks.create_current - end + ActiveRecord::Tasks::DatabaseTasks.create_current end namespace :drop do @@ -33,22 +23,26 @@ db_namespace = namespace :db do end end - desc 'Drops the database using DATABASE_URL or the current Rails.env (use db:drop:all to drop all databases)' + desc 'Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop all databases in the config). Without RAILS_ENV it defaults to dropping the development and test databases.' task :drop => [:load_config] do - if ENV['DATABASE_URL'] - ActiveRecord::Tasks::DatabaseTasks.drop_database_url - else - ActiveRecord::Tasks::DatabaseTasks.drop_current + ActiveRecord::Tasks::DatabaseTasks.drop_current + end + + namespace :purge do + task :all => :load_config do + ActiveRecord::Tasks::DatabaseTasks.purge_all end end + # desc "Empty the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop all databases in the config). Without RAILS_ENV it defaults to purging the development and test databases." + task :purge => [:load_config] do + ActiveRecord::Tasks::DatabaseTasks.purge_current + end + desc "Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)." task :migrate => [:environment, :load_config] do - ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true - ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, ENV["VERSION"] ? ENV["VERSION"].to_i : nil) do |migration| - ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope) - end - db_namespace['_dump'].invoke + ActiveRecord::Tasks::DatabaseTasks.migrate + db_namespace['_dump'].invoke if ActiveRecord::Base.dump_schema_after_migration end task :_dump do @@ -89,29 +83,28 @@ db_namespace = namespace :db do # desc 'Runs the "down" for a given migration VERSION.' task :down => [:environment, :load_config] do version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil - raise 'VERSION is required' unless version + raise 'VERSION is required - To go down one migration, run db:rollback' unless version ActiveRecord::Migrator.run(:down, ActiveRecord::Migrator.migrations_paths, version) db_namespace['_dump'].invoke end desc 'Display status of migrations' task :status => [:environment, :load_config] do - unless ActiveRecord::Base.connection.table_exists?(ActiveRecord::Migrator.schema_migrations_table_name) - puts 'Schema migrations table does not exist yet.' - next # means "return" for rake task + unless ActiveRecord::SchemaMigration.table_exists? + abort 'Schema migrations table does not exist yet.' end - db_list = ActiveRecord::Base.connection.select_values("SELECT version FROM #{ActiveRecord::Migrator.schema_migrations_table_name}") - db_list.map! { |version| "%.3d" % version } - file_list = [] - ActiveRecord::Migrator.migrations_paths.each do |path| - Dir.foreach(path) do |file| - # match "20091231235959_some_name.rb" and "001_some_name.rb" pattern - if match_data = /^(\d{3,})_(.+)\.rb$/.match(file) - status = db_list.delete(match_data[1]) ? 'up' : 'down' - file_list << [status, match_data[1], match_data[2].humanize] + db_list = ActiveRecord::SchemaMigration.normalized_versions + + file_list = + ActiveRecord::Migrator.migrations_paths.flat_map do |path| + # match "20091231235959_some_name.rb" and "001_some_name.rb" pattern + Dir.foreach(path).grep(/^(\d{3,})_(.+)\.rb$/) do + version = ActiveRecord::SchemaMigration.normalize_migration_number($1) + status = db_list.delete(version) ? 'up' : 'down' + [status, version, $2.humanize] + end end - end - end + db_list.map! do |version| ['up', version, '********** NO FILE **********'] end @@ -119,8 +112,8 @@ db_namespace = namespace :db do puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n" puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name" puts "-" * 50 - (db_list + file_list).sort_by {|migration| migration[1]}.each do |migration| - puts "#{migration[0].center(8)} #{migration[1].ljust(14)} #{migration[2]}" + (db_list + file_list).sort_by { |_, version, _| version }.each do |status, version, name| + puts "#{status.center(8)} #{version.ljust(14)} #{name}" end puts end @@ -156,7 +149,7 @@ db_namespace = namespace :db do begin puts ActiveRecord::Tasks::DatabaseTasks.collation_current rescue NoMethodError - $stderr.puts 'Sorry, your database adapter is not supported yet, feel free to submit a patch' + $stderr.puts 'Sorry, your database adapter is not supported yet. Feel free to submit a patch.' end end @@ -166,11 +159,11 @@ db_namespace = namespace :db do end # desc "Raises an error if there are pending migrations" - task :abort_if_pending_migrations => [:environment, :load_config] do + task :abort_if_pending_migrations => :environment do pending_migrations = ActiveRecord::Migrator.open(ActiveRecord::Migrator.migrations_paths).pending_migrations if pending_migrations.any? - puts "You have #{pending_migrations.size} pending migrations:" + puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}" pending_migrations.each do |pending_migration| puts ' %4d %s' % [pending_migration.version, pending_migration.name] end @@ -178,13 +171,13 @@ db_namespace = namespace :db do end end - desc 'Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the db first)' + desc 'Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the database first)' task :setup => ['db:schema:load_if_ruby', 'db:structure:load_if_sql', :seed] desc 'Load the seed data from db/seeds.rb' task :seed do db_namespace['abort_if_pending_migrations'].invoke - Rails.application.load_seed + ActiveRecord::Tasks::DatabaseTasks.load_seed end namespace :fixtures do @@ -192,12 +185,22 @@ db_namespace = namespace :db do task :load => [:environment, :load_config] do require 'active_record/fixtures' - base_dir = File.join [Rails.root, ENV['FIXTURES_PATH'] || %w{test fixtures}].flatten - fixtures_dir = File.join [base_dir, ENV['FIXTURES_DIR']].compact + base_dir = ActiveRecord::Tasks::DatabaseTasks.fixtures_path - (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir["#{fixtures_dir}/**/*.yml"].map {|f| f[(fixtures_dir.size + 1)..-5] }).each do |fixture_file| - ActiveRecord::FixtureSet.create_fixtures(fixtures_dir, fixture_file) - end + fixtures_dir = if ENV['FIXTURES_DIR'] + File.join base_dir, ENV['FIXTURES_DIR'] + else + base_dir + end + + fixture_files = if ENV['FIXTURES'] + ENV['FIXTURES'].split(',') + else + # The use of String#[] here is to support namespaced fixtures + Dir["#{fixtures_dir}/**/*.yml"].map {|f| f[(fixtures_dir.size + 1)..-5] } + end + + ActiveRecord::FixtureSet.create_fixtures(fixtures_dir, fixture_files) end # desc "Search for a fixture given a LABEL or ID. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures." @@ -209,10 +212,11 @@ db_namespace = namespace :db do puts %Q(The fixture ID for "#{label}" is #{ActiveRecord::FixtureSet.identify(label)}.) if label - base_dir = ENV['FIXTURES_PATH'] ? File.join(Rails.root, ENV['FIXTURES_PATH']) : File.join(Rails.root, 'test', 'fixtures') + base_dir = ActiveRecord::Tasks::DatabaseTasks.fixtures_path + Dir["#{base_dir}/**/*.yml"].each do |file| if data = YAML::load(ERB.new(IO.read(file)).result) - data.keys.each do |key| + data.each_key do |key| key_id = ActiveRecord::FixtureSet.identify(key) if key == label || key_id == id.to_i @@ -225,10 +229,10 @@ db_namespace = namespace :db do end namespace :schema do - desc 'Create a db/schema.rb file that can be portably used against any DB supported by AR' + desc 'Create a db/schema.rb file that is portable against any DB supported by AR' task :dump => [:environment, :load_config] do require 'active_record/schema_dumper' - filename = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb" + filename = ENV['SCHEMA'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, 'schema.rb') File.open(filename, "w:utf-8") do |file| ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file) end @@ -236,13 +240,8 @@ db_namespace = namespace :db do end desc 'Load a schema.rb file into the database' - task :load => [:environment, :load_config] do - file = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb" - if File.exists?(file) - load(file) - else - abort %{#{file} doesn't exist yet. Run `rake db:migrate` to create it then try again. 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} - end + task :load => [:load_config] do + ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:ruby, ENV['SCHEMA']) end task :load_if_ruby => ['db:create', :environment] do @@ -253,7 +252,7 @@ db_namespace = namespace :db do desc 'Create a db/schema_cache.dump file.' task :dump => [:environment, :load_config] do con = ActiveRecord::Base.connection - filename = File.join(Rails.application.config.paths["db"].first, "schema_cache.dump") + filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.dump") con.schema_cache.clear! con.tables.each { |table| con.schema_cache.add(table) } @@ -262,72 +261,33 @@ db_namespace = namespace :db do desc 'Clear a db/schema_cache.dump file.' task :clear => [:environment, :load_config] do - filename = File.join(Rails.application.config.paths["db"].first, "schema_cache.dump") - FileUtils.rm(filename) if File.exists?(filename) + filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.dump") + FileUtils.rm(filename) if File.exist?(filename) end end end namespace :structure do - 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 - desc 'Dump the database structure to db/structure.sql. Specify another file with DB_STRUCTURE=db/my_structure.sql' task :dump => [:environment, :load_config] do - filename = ENV['DB_STRUCTURE'] || File.join(Rails.root, "db", "structure.sql") + filename = ENV['DB_STRUCTURE'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "structure.sql") current_config = ActiveRecord::Tasks::DatabaseTasks.current_config - case current_config['adapter'] - when /mysql/, /postgresql/, /sqlite/ - ActiveRecord::Tasks::DatabaseTasks.structure_dump(current_config, filename) - when 'oci', 'oracle' - ActiveRecord::Base.establish_connection(current_config) - File.open(filename, "w:utf-8") { |f| f << ActiveRecord::Base.connection.structure_dump } - when 'sqlserver' - `smoscript -s #{current_config['host']} -d #{current_config['database']} -u #{current_config['username']} -p #{current_config['password']} -f #{filename} -A -U` - when "firebird" - set_firebird_env(current_config) - db_string = firebird_db_string(current_config) - sh "isql -a #{db_string} > #{filename}" - else - raise "Task not supported by '#{current_config["adapter"]}'" - end + ActiveRecord::Tasks::DatabaseTasks.structure_dump(current_config, filename) - if ActiveRecord::Base.connection.supports_migrations? + if ActiveRecord::Base.connection.supports_migrations? && + ActiveRecord::SchemaMigration.table_exists? File.open(filename, "a") do |f| f.puts ActiveRecord::Base.connection.dump_schema_information + f.print "\n" end end db_namespace['structure:dump'].reenable end - # desc "Recreate the databases from the structure.sql file" + desc "Recreate the databases from the structure.sql file" task :load => [:environment, :load_config] do - current_config = ActiveRecord::Tasks::DatabaseTasks.current_config - filename = ENV['DB_STRUCTURE'] || File.join(Rails.root, "db", "structure.sql") - case current_config['adapter'] - when /mysql/, /postgresql/, /sqlite/ - ActiveRecord::Tasks::DatabaseTasks.structure_load(current_config, filename) - when 'sqlserver' - `sqlcmd -S #{current_config['host']} -d #{current_config['database']} -U #{current_config['username']} -P #{current_config['password']} -i #{filename}` - when 'oci', 'oracle' - ActiveRecord::Base.establish_connection(current_config) - IO.read(filename).split(";\n\n").each do |ddl| - ActiveRecord::Base.connection.execute(ddl) - end - when 'firebird' - set_firebird_env(current_config) - db_string = firebird_db_string(current_config) - sh "isql -i #{filename} #{db_string}" - else - raise "Task not supported by '#{current_config['adapter']}'" - end + ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:sql, ENV['DB_STRUCTURE']) end task :load_if_sql => ['db:create', :environment] do @@ -337,8 +297,15 @@ db_namespace = namespace :db do namespace :test do + task :deprecated do + Rake.application.top_level_tasks.grep(/^db:test:/).each do |task| + $stderr.puts "WARNING: #{task} is deprecated. The Rails test helper now maintains " \ + "your test schema automatically, see the release notes for details." + end + end + # desc "Recreate the test database from the current schema" - task :load => 'db:test:purge' do + task :load => %w(db:test:purge) do case ActiveRecord::Base.schema_format when :ruby db_namespace["test:load_schema"].invoke @@ -348,24 +315,25 @@ db_namespace = namespace :db do end # desc "Recreate the test database from an existent schema.rb file" - task :load_schema => 'db:test:purge' do - ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test']) - ActiveRecord::Schema.verbose = false - db_namespace["schema:load"].invoke - end - - # desc "Recreate the test database from an existent structure.sql file" - task :load_structure => 'db:test:purge' do + task :load_schema => %w(db:test:purge) do begin - ActiveRecord::Tasks::DatabaseTasks.current_config(:config => ActiveRecord::Base.configurations['test']) - db_namespace["structure:load"].invoke + should_reconnect = ActiveRecord::Base.connection_pool.active_connection? + ActiveRecord::Schema.verbose = false + ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations['test'], :ruby, ENV['SCHEMA'] ensure - ActiveRecord::Tasks::DatabaseTasks.current_config(:config => nil) + if should_reconnect + ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[ActiveRecord::Tasks::DatabaseTasks.env]) + end end end + # desc "Recreate the test database from an existent structure.sql file" + task :load_structure => %w(db:test:purge) do + ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations['test'], :sql, ENV['SCHEMA'] + end + # desc "Recreate the test database from a fresh schema" - task :clone do + task :clone => %w(db:test:deprecated environment) do case ActiveRecord::Base.schema_format when :ruby db_namespace["test:clone_schema"].invoke @@ -375,38 +343,18 @@ db_namespace = namespace :db do end # desc "Recreate the test database from a fresh schema.rb file" - task :clone_schema => ["db:schema:dump", "db:test:load_schema"] + task :clone_schema => %w(db:test:deprecated db:schema:dump db:test:load_schema) # desc "Recreate the test database from a fresh structure.sql file" - task :clone_structure => [ "db:structure:dump", "db:test:load_structure" ] + task :clone_structure => %w(db:test:deprecated db:structure:dump db:test:load_structure) # desc "Empty the test database" - task :purge => [:environment, :load_config] do - abcs = ActiveRecord::Base.configurations - case abcs['test']['adapter'] - when /mysql/, /postgresql/, /sqlite/ - ActiveRecord::Tasks::DatabaseTasks.purge abcs['test'] - when 'sqlserver' - test = abcs.deep_dup['test'] - test_database = test['database'] - test['database'] = 'master' - ActiveRecord::Base.establish_connection(test) - ActiveRecord::Base.connection.recreate_database!(test_database) - when "oci", "oracle" - ActiveRecord::Base.establish_connection(:test) - ActiveRecord::Base.connection.structure_drop.split(";\n\n").each do |ddl| - ActiveRecord::Base.connection.execute(ddl) - end - when 'firebird' - ActiveRecord::Base.establish_connection(:test) - ActiveRecord::Base.connection.recreate_database! - else - raise "Task not supported by '#{abcs['test']['adapter']}'" - end + task :purge => %w(environment load_config) do + ActiveRecord::Tasks::DatabaseTasks.purge ActiveRecord::Base.configurations['test'] end # desc 'Check for pending migrations and load the test schema' - task :prepare => 'db:abort_if_pending_migrations' do + task :prepare => %w(environment load_config) do unless ActiveRecord::Base.configurations.blank? db_namespace['test:load'].invoke end @@ -418,9 +366,9 @@ namespace :railties do namespace :install do # desc "Copies missing migrations from Railties (e.g. engines). You can specify Railties to use with FROM=railtie1,railtie2" task :migrations => :'db:load_config' do - to_load = ENV['FROM'].blank? ? :all : ENV['FROM'].split(",").map {|n| n.strip } + to_load = ENV['FROM'].blank? ? :all : ENV['FROM'].split(",").map(&:strip) railties = {} - Rails.application.railties.each do |railtie| + Rails.application.migration_railties.each do |railtie| next unless to_load == :all || to_load.include?(railtie.railtie_name) if railtie.respond_to?(:paths) && (path = railtie.paths['db/migrate'].first) @@ -432,7 +380,7 @@ namespace :railties do puts "NOTE: Migration #{migration.basename} from #{name} has been skipped. Migration with the same name already exists." end - on_copy = Proc.new do |name, migration, old_path| + on_copy = Proc.new do |name, migration| puts "Copied migration #{migration.basename} from #{name}" end @@ -441,6 +389,3 @@ namespace :railties do end end end - -task 'test:prepare' => 'db:test:prepare' - |