databases.rake 15.3 KB
Newer Older
1
require 'active_record'
2

3
db_namespace = namespace :db do
4
  task :load_config do
5
    ActiveRecord::Base.configurations       = ActiveRecord::Tasks::DatabaseTasks.database_configuration || {}
6
    ActiveRecord::Migrator.migrations_paths = ActiveRecord::Tasks::DatabaseTasks.migrations_paths
7 8
  end

9
  namespace :create do
10
    task :all => :load_config do
11
      ActiveRecord::Tasks::DatabaseTasks.create_all
12 13 14
    end
  end

15
  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.'
16
  task :create => [:load_config] do
17
    ActiveRecord::Tasks::DatabaseTasks.create_current
18
  end
19

20
  namespace :drop do
21
    task :all => :load_config do
22
      ActiveRecord::Tasks::DatabaseTasks.drop_all
23 24
    end
  end
25

26
  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.'
27
  task :drop => [:load_config] do
28
    ActiveRecord::Tasks::DatabaseTasks.drop_current
29 30
  end

31 32 33 34 35 36 37 38 39 40 41
  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

K
kennyj 已提交
42
  desc "Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)."
43
  task :migrate => [:environment, :load_config] do
44
    ActiveRecord::Tasks::DatabaseTasks.migrate
45
    db_namespace['_dump'].invoke if ActiveRecord::Base.dump_schema_after_migration
A
Aaron Patterson 已提交
46 47 48 49 50 51 52 53 54
  end

  task :_dump do
    case ActiveRecord::Base.schema_format
    when :ruby then db_namespace["schema:dump"].invoke
    when :sql  then db_namespace["structure:dump"].invoke
    else
      raise "unknown schema format #{ActiveRecord::Base.schema_format}"
    end
55 56 57
    # Allow this task to be called as many times as required. An example is the
    # migrate:redo task, which calls other two internally that depend on this one.
    db_namespace['_dump'].reenable
58 59
  end

60
  namespace :migrate do
61
    # desc  'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).'
62
    task :redo => [:environment, :load_config] do
A
Arun Agrawal 已提交
63 64 65
      if ENV['VERSION']
        db_namespace['migrate:down'].invoke
        db_namespace['migrate:up'].invoke
66
      else
A
Arun Agrawal 已提交
67 68
        db_namespace['rollback'].invoke
        db_namespace['migrate'].invoke
69 70
      end
    end
71

72
    # desc 'Resets your database using your migrations for the current environment'
A
Arun Agrawal 已提交
73
    task :reset => ['db:drop', 'db:create', 'db:migrate']
74

75
    # desc 'Runs the "up" for a given migration VERSION.'
76
    task :up => [:environment, :load_config] do
A
Arun Agrawal 已提交
77 78
      version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
      raise 'VERSION is required' unless version
79
      ActiveRecord::Migrator.run(:up, ActiveRecord::Migrator.migrations_paths, version)
A
Aaron Patterson 已提交
80
      db_namespace['_dump'].invoke
81 82
    end

83
    # desc 'Runs the "down" for a given migration VERSION.'
84
    task :down => [:environment, :load_config] do
A
Arun Agrawal 已提交
85
      version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
86
      raise 'VERSION is required - To go down one migration, run db:rollback' unless version
87
      ActiveRecord::Migrator.run(:down, ActiveRecord::Migrator.migrations_paths, version)
A
Aaron Patterson 已提交
88
      db_namespace['_dump'].invoke
89
    end
90

A
Arun Agrawal 已提交
91
    desc 'Display status of migrations'
92
    task :status => [:environment, :load_config] do
93
      unless ActiveRecord::SchemaMigration.table_exists?
94
        abort 'Schema migrations table does not exist yet.'
95
      end
96
      db_list = ActiveRecord::SchemaMigration.normalized_versions
97 98 99 100 101 102 103 104 105

      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
106
          end
107

108 109 110
      db_list.map! do |version|
        ['up', version, '********** NO FILE **********']
      end
111
      # output
112
      puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n"
A
Arun Agrawal 已提交
113
      puts "#{'Status'.center(8)}  #{'Migration ID'.ljust(14)}  Migration Name"
114
      puts "-" * 50
115 116
      (db_list + file_list).sort_by { |_, version, _| version }.each do |status, version, name|
        puts "#{status.center(8)}  #{version.ljust(14)}  #{name}"
117 118 119
      end
      puts
    end
120 121
  end

122
  desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n).'
123
  task :rollback => [:environment, :load_config] do
124
    step = ENV['STEP'] ? ENV['STEP'].to_i : 1
125
    ActiveRecord::Migrator.rollback(ActiveRecord::Migrator.migrations_paths, step)
A
Aaron Patterson 已提交
126
    db_namespace['_dump'].invoke
127 128
  end

129
  # desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
130
  task :forward => [:environment, :load_config] do
131
    step = ENV['STEP'] ? ENV['STEP'].to_i : 1
132
    ActiveRecord::Migrator.forward(ActiveRecord::Migrator.migrations_paths, step)
A
Aaron Patterson 已提交
133
    db_namespace['_dump'].invoke
134 135
  end

136
  # desc 'Drops and recreates the database from db/schema.rb for the current environment and loads the seeds.'
137
  task :reset => [:environment, :load_config] do
138 139 140
    db_namespace["drop"].invoke
    db_namespace["setup"].invoke
  end
141

142
  # desc "Retrieves the charset for the current environment's database"
143
  task :charset => [:environment, :load_config] do
S
Simon Jefford 已提交
144
    puts ActiveRecord::Tasks::DatabaseTasks.charset_current
145 146
  end

147
  # desc "Retrieves the collation for the current environment's database"
148
  task :collation => [:environment, :load_config] do
149 150 151
    begin
      puts ActiveRecord::Tasks::DatabaseTasks.collation_current
    rescue NoMethodError
152
      $stderr.puts 'Sorry, your database adapter is not supported yet. Feel free to submit a patch.'
153
    end
154
  end
155

A
Arun Agrawal 已提交
156
  desc 'Retrieves the current schema version number'
157
  task :version => [:environment, :load_config] do
158
    puts "Current version: #{ActiveRecord::Migrator.current_version}"
159 160
  end

161
  # desc "Raises an error if there are pending migrations"
162
  task :abort_if_pending_migrations => :environment do
163
    pending_migrations = ActiveRecord::Migrator.open(ActiveRecord::Migrator.migrations_paths).pending_migrations
164

165
    if pending_migrations.any?
166
      puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
167 168
      pending_migrations.each do |pending_migration|
        puts '  %4d %s' % [pending_migration.version, pending_migration.name]
169
      end
170
      abort %{Run `rake db:migrate` to update your database then try again.}
171 172 173
    end
  end

174
  desc 'Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the database first)'
175
  task :setup => ['db:schema:load_if_ruby', 'db:structure:load_if_sql', :seed]
176 177

  desc 'Load the seed data from db/seeds.rb'
178
  task :seed do
179
    db_namespace['abort_if_pending_migrations'].invoke
180
    ActiveRecord::Tasks::DatabaseTasks.load_seed
181 182
  end

183
  namespace :fixtures do
184
    desc "Load fixtures into the current environment's database. Load specific fixtures using FIXTURES=x,y. Load from subdirectory in test/fixtures using FIXTURES_DIR=z. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
185
    task :load => [:environment, :load_config] do
186 187
      require 'active_record/fixtures'

188
      base_dir = ActiveRecord::Tasks::DatabaseTasks.fixtures_path
189

190 191 192 193 194
      fixtures_dir = if ENV['FIXTURES_DIR']
                       File.join base_dir, ENV['FIXTURES_DIR']
                     else
                       base_dir
                     end
195

196 197 198
      fixture_files = if ENV['FIXTURES']
                        ENV['FIXTURES'].split(',')
                      else
199
                        # The use of String#[] here is to support namespaced fixtures
200
                        Dir["#{fixtures_dir}/**/*.yml"].map {|f| f[(fixtures_dir.size + 1)..-5] }
201 202
                      end

203
      ActiveRecord::FixtureSet.create_fixtures(fixtures_dir, fixture_files)
204
    end
205

206
    # desc "Search for a fixture given a LABEL or ID. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
207
    task :identify => [:environment, :load_config] do
208 209
      require 'active_record/fixtures'

A
Arun Agrawal 已提交
210 211
      label, id = ENV['LABEL'], ENV['ID']
      raise 'LABEL or ID required' if label.blank? && id.blank?
212

213
      puts %Q(The fixture ID for "#{label}" is #{ActiveRecord::FixtureSet.identify(label)}.) if label
214

215
      base_dir = ActiveRecord::Tasks::DatabaseTasks.fixtures_path
216

217
      Dir["#{base_dir}/**/*.yml"].each do |file|
218
        if data = YAML::load(ERB.new(IO.read(file)).result)
219
          data.each_key do |key|
220
            key_id = ActiveRecord::FixtureSet.identify(key)
221

222 223 224 225 226 227 228
            if key == label || key_id == id.to_i
              puts "#{file}: #{key} (#{key_id})"
            end
          end
        end
      end
    end
229
  end
230

231
  namespace :schema do
232
    desc 'Create a db/schema.rb file that is portable against any DB supported by AR'
233
    task :dump => [:environment, :load_config] do
234
      require 'active_record/schema_dumper'
235
      filename = ENV['SCHEMA'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, 'schema.rb')
236
      File.open(filename, "w:utf-8") do |file|
237 238
        ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
      end
A
Arun Agrawal 已提交
239
      db_namespace['schema:dump'].reenable
240
    end
241

A
Arun Agrawal 已提交
242
    desc 'Load a schema.rb file into the database'
243
    task :load => [:load_config] do
244
      ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:ruby, ENV['SCHEMA'])
245
    end
246

247
    task :load_if_ruby => ['db:create', :environment] do
248 249
      db_namespace["schema:load"].invoke if ActiveRecord::Base.schema_format == :ruby
    end
250 251 252

    namespace :cache do
      desc 'Create a db/schema_cache.dump file.'
253
      task :dump => [:environment, :load_config] do
254
        con = ActiveRecord::Base.connection
255
        filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.dump")
256 257 258 259 260 261 262

        con.schema_cache.clear!
        con.tables.each { |table| con.schema_cache.add(table) }
        open(filename, 'wb') { |f| f.write(Marshal.dump(con.schema_cache)) }
      end

      desc 'Clear a db/schema_cache.dump file.'
263
      task :clear => [:environment, :load_config] do
264
        filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.dump")
A
Arun Agrawal 已提交
265
        FileUtils.rm(filename) if File.exist?(filename)
266 267 268
      end
    end

269 270
  end

271
  namespace :structure do
V
Vijay Dev 已提交
272
    desc 'Dump the database structure to db/structure.sql. Specify another file with DB_STRUCTURE=db/my_structure.sql'
273
    task :dump => [:environment, :load_config] do
274
      filename = ENV['DB_STRUCTURE'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "structure.sql")
275
      current_config = ActiveRecord::Tasks::DatabaseTasks.current_config
K
kennyj 已提交
276
      ActiveRecord::Tasks::DatabaseTasks.structure_dump(current_config, filename)
277

278 279
      if ActiveRecord::Base.connection.supports_migrations? &&
          ActiveRecord::SchemaMigration.table_exists?
280 281
        File.open(filename, "a") do |f|
          f.puts ActiveRecord::Base.connection.dump_schema_information
C
Chad Jolly 已提交
282
          f.print "\n"
283
        end
284
      end
285
      db_namespace['structure:dump'].reenable
286
    end
287

288
    desc "Recreate the databases from the structure.sql file"
289
    task :load => [:environment, :load_config] do
290
      ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:sql, ENV['DB_STRUCTURE'])
291
    end
292

293
    task :load_if_sql => ['db:create', :environment] do
294 295
      db_namespace["structure:load"].invoke if ActiveRecord::Base.schema_format == :sql
    end
296 297 298
  end

  namespace :test do
299

300 301 302 303 304 305 306
    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

307
    # desc "Recreate the test database from the current schema"
Y
Yves Senn 已提交
308
    task :load => %w(db:test:purge) do
309 310 311 312 313
      case ActiveRecord::Base.schema_format
        when :ruby
          db_namespace["test:load_schema"].invoke
        when :sql
          db_namespace["test:load_structure"].invoke
314
      end
315
    end
316

317
    # desc "Recreate the test database from an existent schema.rb file"
Y
Yves Senn 已提交
318
    task :load_schema => %w(db:test:purge) do
319
      begin
320
        should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
321
        ActiveRecord::Schema.verbose = false
322
        ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations['test'], :ruby, ENV['SCHEMA']
323
      ensure
324 325 326
        if should_reconnect
          ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[ActiveRecord::Tasks::DatabaseTasks.env])
        end
327
      end
328 329
    end

330
    # desc "Recreate the test database from an existent structure.sql file"
Y
Yves Senn 已提交
331
    task :load_structure => %w(db:test:purge) do
332
      ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations['test'], :sql, ENV['SCHEMA']
333
    end
334

335
    # desc "Recreate the test database from a fresh schema"
336
    task :clone => %w(db:test:deprecated environment) do
337 338 339 340 341 342 343 344
      case ActiveRecord::Base.schema_format
        when :ruby
          db_namespace["test:clone_schema"].invoke
        when :sql
          db_namespace["test:clone_structure"].invoke
      end
    end

345
    # desc "Recreate the test database from a fresh schema.rb file"
346
    task :clone_schema => %w(db:test:deprecated db:schema:dump db:test:load_schema)
347

348
    # desc "Recreate the test database from a fresh structure.sql file"
349
    task :clone_structure => %w(db:test:deprecated db:structure:dump db:test:load_structure)
350

351
    # desc "Empty the test database"
Y
Yves Senn 已提交
352
    task :purge => %w(environment load_config) do
K
kennyj 已提交
353
      ActiveRecord::Tasks::DatabaseTasks.purge ActiveRecord::Base.configurations['test']
354
    end
355

356
    # desc 'Check for pending migrations and load the test schema'
Y
Yves Senn 已提交
357
    task :prepare => %w(environment load_config) do
358
      unless ActiveRecord::Base.configurations.blank?
359
        db_namespace['test:load'].invoke
360
      end
361
    end
362 363 364
  end
end

365
namespace :railties do
366
  namespace :install do
S
Santiago Pastorino 已提交
367
    # desc "Copies missing migrations from Railties (e.g. engines). You can specify Railties to use with FROM=railtie1,railtie2"
A
Arun Agrawal 已提交
368
    task :migrations => :'db:load_config' do
369
      to_load = ENV['FROM'].blank? ? :all : ENV['FROM'].split(",").map(&:strip)
R
Raghunadh 已提交
370
      railties = {}
371
      Rails.application.migration_railties.each do |railtie|
372 373
        next unless to_load == :all || to_load.include?(railtie.railtie_name)

A
Arun Agrawal 已提交
374
        if railtie.respond_to?(:paths) && (path = railtie.paths['db/migrate'].first)
375 376 377 378 379
          railties[railtie.railtie_name] = path
        end
      end

      on_skip = Proc.new do |name, migration|
380
        puts "NOTE: Migration #{migration.basename} from #{name} has been skipped. Migration with the same name already exists."
381 382
      end

383
      on_copy = Proc.new do |name, migration|
384 385 386
        puts "Copied migration #{migration.basename} from #{name}"
      end

387
      ActiveRecord::Migration.copy(ActiveRecord::Migrator.migrations_paths.first, railties,
388 389 390
                                    :on_skip => on_skip, :on_copy => on_copy)
    end
  end
391
end