1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Merge remote branch 'drogus/engines'

This commit is contained in:
José Valim 2010-10-10 14:57:19 +02:00
commit 621df2a1ec
14 changed files with 205 additions and 90 deletions

View file

@ -384,23 +384,32 @@ module ActiveRecord
end
end
def copy(destination, sources)
def copy(destination, sources, options = {})
copied = []
sources.each do |scope, path|
destination_migrations = ActiveRecord::Migrator.migrations(destination)
destination_migrations = ActiveRecord::Migrator.migrations(destination)
last = destination_migrations.last
sources.each do |name, path|
source_migrations = ActiveRecord::Migrator.migrations(path)
last = destination_migrations.last
source_migrations.each do |migration|
next if destination_migrations.any? { |m| m.name == migration.name && m.scope == scope.to_s }
source = File.read(migration.filename)
source = "# This migration comes from #{name} (originally #{migration.version})\n#{source}"
if duplicate = destination_migrations.detect { |m| m.name == migration.name }
options[:on_skip].call(name, migration) if File.read(duplicate.filename) != source && options[:on_skip]
next
end
migration.version = next_migration_number(last ? last.version + 1 : 0).to_i
new_path = File.join(destination, "#{migration.version}_#{migration.name.underscore}.rb")
old_path, migration.filename = migration.filename, new_path
last = migration
new_path = File.join(destination, "#{migration.version}_#{migration.name.underscore}.#{scope}.rb")
FileUtils.cp(migration.filename, new_path)
copied << new_path
FileUtils.cp(old_path, migration.filename)
copied << migration
options[:on_copy].call(name, migration, old_path) if options[:on_copy]
destination_migrations << migration
end
end
@ -419,13 +428,17 @@ module ActiveRecord
# MigrationProxy is used to defer loading of the actual migration classes
# until they are needed
class MigrationProxy < Struct.new(:name, :version, :filename, :scope)
class MigrationProxy < Struct.new(:name, :version, :filename)
def initialize(name, version, filename, scope)
def initialize(name, version, filename)
super
@migration = nil
end
def basename
File.basename(filename)
end
delegate :migrate, :announce, :write, :to=>:migration
private
@ -510,18 +523,18 @@ module ActiveRecord
seen = Hash.new false
migrations = files.map do |file|
version, name, scope = file.scan(/([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?.rb/).first
version, name = file.scan(/([0-9]+)_([_a-z0-9]*).rb/).first
raise IllegalMigrationNameError.new(file) unless version
version = version.to_i
name = name.camelize
raise DuplicateMigrationVersionError.new(version) if seen[version]
raise DuplicateMigrationNameError.new(name) if seen[[name, scope]]
raise DuplicateMigrationNameError.new(name) if seen[name]
seen[version] = seen[[name, scope]] = true
seen[version] = seen[name] = true
MigrationProxy.new(name, version, file, scope)
MigrationProxy.new(name, version, file)
end
migrations.sort_by(&:version)

View file

@ -5,27 +5,6 @@ namespace :db do
ActiveRecord::Migrator.migrations_path = Rails.application.paths["db/migrate"].first
end
task :copy_migrations => :load_config do
to_load = ENV["FROM"].blank? ? :all : ENV["FROM"].split(",").map {|n| n.strip }
railties = {}
Rails.application.railties.all do |railtie|
next unless to_load == :all || to_load.include?(railtie.railtie_name)
if railtie.respond_to?(:paths) && (path = railtie.paths["db/migrate"].first)
railties[railtie.railtie_name] = path
end
end
copied = ActiveRecord::Migration.copy(ActiveRecord::Migrator.migrations_path, railties)
if copied.blank?
puts "No migrations were copied, project is up to date."
else
puts "The following migrations were copied:"
puts copied.map{ |path| File.basename(path) }.join("\n")
end
end
namespace :create do
# desc 'Create all the local databases defined in config/database.yml'
task :all => :load_config do
@ -501,8 +480,31 @@ namespace :db do
end
namespace :railties do
desc "Copies missing migrations from Railties (e.g. plugins, engines). You can specify Railties to use with FROM=railtie1,railtie2"
task :copy_migrations => 'db:copy_migrations'
namespace :install do
desc "Copies missing migrations from Railties (e.g. plugins, 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 }
railties = {}
Rails.application.railties.all do |railtie|
next unless to_load == :all || to_load.include?(railtie.railtie_name)
if railtie.respond_to?(:paths) && (path = railtie.paths["db/migrate"].first)
railties[railtie.railtie_name] = path
end
end
on_skip = Proc.new do |name, migration|
$stderr.puts "WARNING: 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|
puts "Copied migration #{migration.basename} from #{name}"
end
ActiveRecord::Migration.copy( ActiveRecord::Migrator.migrations_path, railties,
:on_skip => on_skip, :on_copy => on_copy)
end
end
end
task 'test:prepare' => 'db:test:prepare'

View file

@ -1910,9 +1910,9 @@ if ActiveRecord::Base.connection.supports_migrations?
@existing_migrations = Dir[@migrations_path + "/*.rb"]
copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy"})
assert File.exists?(@migrations_path + "/4_people_have_hobbies.bukkits.rb")
assert File.exists?(@migrations_path + "/5_people_have_descriptions.bukkits.rb")
assert_equal [@migrations_path + "/4_people_have_hobbies.bukkits.rb", @migrations_path + "/5_people_have_descriptions.bukkits.rb"], copied
assert File.exists?(@migrations_path + "/4_people_have_hobbies.rb")
assert File.exists?(@migrations_path + "/5_people_have_descriptions.rb")
assert_equal [@migrations_path + "/4_people_have_hobbies.rb", @migrations_path + "/5_people_have_descriptions.rb"], copied.map(&:filename)
files_count = Dir[@migrations_path + "/*.rb"].length
copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy"})
@ -1928,12 +1928,13 @@ if ActiveRecord::Base.connection.supports_migrations?
@existing_migrations = Dir[@migrations_path + "/*.rb"]
sources = ActiveSupport::OrderedHash.new
sources[:bukkits] = sources[:omg] = MIGRATIONS_ROOT + "/to_copy"
sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy"
sources[:omg] = MIGRATIONS_ROOT + "/to_copy2"
ActiveRecord::Migration.copy(@migrations_path, sources)
assert File.exists?(@migrations_path + "/4_people_have_hobbies.omg.rb")
assert File.exists?(@migrations_path + "/5_people_have_descriptions.omg.rb")
assert File.exists?(@migrations_path + "/6_people_have_hobbies.bukkits.rb")
assert File.exists?(@migrations_path + "/7_people_have_descriptions.bukkits.rb")
assert File.exists?(@migrations_path + "/4_people_have_hobbies.rb")
assert File.exists?(@migrations_path + "/5_people_have_descriptions.rb")
assert File.exists?(@migrations_path + "/6_create_articles.rb")
assert File.exists?(@migrations_path + "/7_create_comments.rb")
files_count = Dir[@migrations_path + "/*.rb"].length
ActiveRecord::Migration.copy(@migrations_path, sources)
@ -1948,11 +1949,11 @@ if ActiveRecord::Base.connection.supports_migrations?
Time.travel_to(created_at = Time.utc(2010, 7, 26, 10, 10, 10)) do
copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
expected = [@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb",
@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb"]
assert_equal expected, copied
assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.rb")
assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.rb")
expected = [@migrations_path + "/20100726101010_people_have_hobbies.rb",
@migrations_path + "/20100726101011_people_have_descriptions.rb"]
assert_equal expected, copied.map(&:filename)
files_count = Dir[@migrations_path + "/*.rb"].length
copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
@ -1968,14 +1969,15 @@ if ActiveRecord::Base.connection.supports_migrations?
@existing_migrations = Dir[@migrations_path + "/*.rb"]
sources = ActiveSupport::OrderedHash.new
sources[:bukkits] = sources[:omg] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
sources[:omg] = MIGRATIONS_ROOT + "/to_copy_with_timestamps2"
Time.travel_to(created_at = Time.utc(2010, 7, 26, 10, 10, 10)) do
copied = ActiveRecord::Migration.copy(@migrations_path, sources)
assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.omg.rb")
assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.omg.rb")
assert File.exists?(@migrations_path + "/20100726101012_people_have_hobbies.bukkits.rb")
assert File.exists?(@migrations_path + "/20100726101013_people_have_descriptions.bukkits.rb")
assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.rb")
assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.rb")
assert File.exists?(@migrations_path + "/20100726101012_create_articles.rb")
assert File.exists?(@migrations_path + "/20100726101013_create_comments.rb")
assert_equal 4, copied.length
files_count = Dir[@migrations_path + "/*.rb"].length
@ -1992,8 +1994,8 @@ if ActiveRecord::Base.connection.supports_migrations?
Time.travel_to(created_at = Time.utc(2010, 2, 20, 10, 10, 10)) do
ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
assert File.exists?(@migrations_path + "/20100301010102_people_have_hobbies.bukkits.rb")
assert File.exists?(@migrations_path + "/20100301010103_people_have_descriptions.bukkits.rb")
assert File.exists?(@migrations_path + "/20100301010102_people_have_hobbies.rb")
assert File.exists?(@migrations_path + "/20100301010103_people_have_descriptions.rb")
files_count = Dir[@migrations_path + "/*.rb"].length
copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
@ -2004,14 +2006,32 @@ if ActiveRecord::Base.connection.supports_migrations?
clear
end
def test_skipping_migrations
@migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
@existing_migrations = Dir[@migrations_path + "/*.rb"]
sources = ActiveSupport::OrderedHash.new
sources[:bukkits] = sources[:omg] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
skipped = []
on_skip = Proc.new { |name, migration| skipped << "#{name} #{migration.name}" }
copied = ActiveRecord::Migration.copy(@migrations_path, sources, :on_skip => on_skip)
assert_equal 2, copied.length
assert_equal 2, skipped.length
assert_equal ["bukkits PeopleHaveHobbies", "bukkits PeopleHaveDescriptions"], skipped
ensure
clear
end
def test_copying_migrations_to_empty_directory
@migrations_path = MIGRATIONS_ROOT + "/empty"
@existing_migrations = []
Time.travel_to(created_at = Time.utc(2010, 7, 26, 10, 10, 10)) do
copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.rb")
assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.rb")
assert_equal 2, copied.length
end
ensure

View file

@ -0,0 +1,7 @@
class CreateArticles < ActiveRecord::Migration
def self.up
end
def self.down
end
end

View file

@ -0,0 +1,7 @@
class CreateArticles < ActiveRecord::Migration
def self.up
end
def self.down
end
end

View file

@ -0,0 +1,7 @@
class CreateArticles < ActiveRecord::Migration
def self.up
end
def self.down
end
end

View file

@ -0,0 +1,7 @@
class CreateComments < ActiveRecord::Migration
def self.up
end
def self.down
end
end

View file

@ -214,11 +214,11 @@ module Rails
# as they would be created inside application. One of the cosequences of that is including
# application's helpers and url_helpers inside controller. Sometimes, especially when your
# engine provides its own routes, you don't want that. To isolate engine's stuff from application
# you can use namespace method:
# you can use isolate_namespace method:
#
# module MyEngine
# class Engine < Rails::Engine
# namespace MyEngine
# isolate_namespace MyEngine
# end
# end
#
@ -252,7 +252,7 @@ module Rails
# end
#
#
# Additionaly namespaced engine will set its name according to namespace, so in that case:
# Additionaly isolated engine will set its name according to namespace, so in that case:
# MyEngine::Engine.engine_name #=> "my_engine" and it will set MyEngine.table_name_prefix
# to "my_engine_".
#
@ -315,7 +315,7 @@ module Rails
autoload :Configuration, "rails/engine/configuration"
class << self
attr_accessor :called_from, :namespaced
attr_accessor :called_from, :isolated
alias :engine_name :railtie_name
def inherited(base)
@ -350,12 +350,12 @@ module Rails
@endpoint
end
def namespace(mod)
def isolate_namespace(mod)
engine_name(generate_railtie_name(mod))
name = engine_name
self.routes.default_scope = {:module => name}
self.namespaced = true
self.isolated = true
unless mod.respond_to?(:_railtie)
_railtie = self
@ -371,13 +371,13 @@ module Rails
end
end
def namespaced?
!!namespaced
def isolated?
!!isolated
end
end
delegate :middleware, :root, :paths, :to => :config
delegate :engine_name, :namespaced?, :to => "self.class"
delegate :engine_name, :isolated?, :to => "self.class"
def load_tasks
super
@ -506,7 +506,7 @@ module Rails
end
initializer :prepend_helpers_path do |app|
if !namespaced? || (app == self)
if !isolated? || (app == self)
app.config.helpers_paths.unshift(*paths["app/helpers"].existent)
end
end
@ -522,6 +522,20 @@ module Rails
# consistently executed after all the initializers above across all engines.
end
rake_tasks do
next if self.is_a?(Rails::Application)
namespace railtie_name do
namespace :install do
desc "Copy migrations from #{railtie_name} to application"
task :migrations do
ENV["FROM"] = railtie_name
Rake::Task["railties:install:migrations"].invoke
end
end
end
end
protected
def routes?
defined?(@routes)

View file

@ -191,6 +191,13 @@ module Rails
def load_tasks
self.class.rake_tasks.each(&:call)
# load also tasks from all superclasses
klass = self.class.superclass
while klass.respond_to?(:rake_tasks)
klass.rake_tasks.each { |t| self.instance_exec(&t) }
klass = klass.superclass
end
end
def load_generators

View file

@ -6,14 +6,14 @@ require 'rails/generators/mailer/mailer_generator'
class NamespacedGeneratorTestCase < Rails::Generators::TestCase
def setup
TestApp::Application.namespace(TestApp)
TestApp::Application.isolate_namespace(TestApp)
end
def teardown
if TestApp.respond_to?(:_railtie)
TestApp.singleton_class.send(:undef_method, :_railtie)
TestApp.singleton_class.send(:undef_method, :table_name_prefix)
TestApp::Application.namespaced = false
TestApp::Application.isolated = false
end
end
end

View file

@ -394,7 +394,7 @@ module RailtiesTest
@plugin.write "lib/bukkits.rb", <<-RUBY
module Bukkits
class Engine < ::Rails::Engine
namespace Bukkits
isolate_namespace Bukkits
end
end
RUBY
@ -511,7 +511,7 @@ module RailtiesTest
@plugin.write "lib/bukkits.rb", <<-RUBY
module Bukkits
class Engine < ::Rails::Engine
namespace Bukkits
isolate_namespace Bukkits
end
end
RUBY
@ -572,7 +572,7 @@ module RailtiesTest
@plugin.write "lib/bukkits.rb", <<-RUBY
module Bukkits
class Engine < ::Rails::Engine
namespace(Bukkits)
isolate_namespace(Bukkits)
end
end
RUBY
@ -593,7 +593,7 @@ module RailtiesTest
@plugin.write "lib/bukkits.rb", <<-RUBY
module Bukkits
class Engine < ::Rails::Engine
namespace(Bukkits)
isolate_namespace(Bukkits)
paths["public"] = "#{File.join(@plugin.path, "alternate_public")}"
end
end
@ -611,7 +611,7 @@ module RailtiesTest
@plugin.write "lib/bukkits.rb", <<-RUBY
module Bukkits
class Engine < ::Rails::Engine
namespace(Bukkits)
isolate_namespace(Bukkits)
paths["public"] = "#{File.join(@plugin.path, "not_existing")}"
end
end
@ -648,12 +648,12 @@ module RailtiesTest
@plugin.write "lib/bukkits.rb", <<-RUBY
module AppTemplate
class Engine < ::Rails::Engine
namespace(AppTemplate)
isolate_namespace(AppTemplate)
end
end
RUBY
add_to_config "namespace AppTemplate"
add_to_config "isolate_namespace AppTemplate"
app_file "config/routes.rb", <<-RUBY
AppTemplate::Application.routes.draw do end
@ -686,7 +686,7 @@ module RailtiesTest
@plugin.write "lib/bukkits.rb", <<-RUBY
module Bukkits
class Engine < ::Rails::Engine
namespace(Bukkits)
isolate_namespace(Bukkits)
end
end
RUBY

View file

@ -49,7 +49,7 @@ module ApplicationTests
@plugin.write "lib/blog.rb", <<-RUBY
module Blog
class Engine < ::Rails::Engine
namespace(Blog)
isolate_namespace(Blog)
end
end
RUBY

View file

@ -103,6 +103,30 @@ module RailtiesTest
assert $ran_block
end
test "rake_tasks block defined in superclass of railtie is also executed" do
$ran_block = []
class Rails::Railtie
rake_tasks do
$ran_block << railtie_name
end
end
class MyTie < Rails::Railtie
railtie_name "my_tie"
end
require "#{app_path}/config/environment"
assert_equal [], $ran_block
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
AppTemplate::Application.load_tasks
assert $ran_block.include?("my_tie")
end
test "generators block is executed when MyApp.load_generators is called" do
$ran_block = false

View file

@ -21,6 +21,11 @@ module RailtiesTest
end
RUBY
@plugin.write "db/migrate/3_create_sessions.rb", <<-RUBY
class CreateSessions < ActiveRecord::Migration
end
RUBY
app_file "db/migrate/1_create_sessions.rb", <<-RUBY
class CreateSessions < ActiveRecord::Migration
end
@ -38,24 +43,26 @@ module RailtiesTest
add_to_config "ActiveRecord::Base.timestamped_migrations = false"
Dir.chdir(app_path) do
output = `rake railties:copy_migrations FROM=bukkits`
output = `rake bukkits:install:migrations 2>&1`
assert File.exists?("#{app_path}/db/migrate/2_create_users.bukkits.rb")
assert File.exists?("#{app_path}/db/migrate/3_add_last_name_to_users.bukkits.rb")
assert_match /2_create_users/, output
assert_match /3_add_last_name_to_users/, output
assert File.exists?("#{app_path}/db/migrate/2_create_users.rb")
assert File.exists?("#{app_path}/db/migrate/3_add_last_name_to_users.rb")
assert_match /Copied migration 2_create_users.rb from bukkits/, output
assert_match /Copied migration 3_add_last_name_to_users.rb from bukkits/, output
assert_match /WARNING: Migration 3_create_sessions.rb from bukkits has been skipped/, output
assert_equal 3, Dir["#{app_path}/db/migrate/*.rb"].length
output = `rake railties:copy_migrations`
output = `rake railties:install:migrations 2>&1`
assert File.exists?("#{app_path}/db/migrate/4_create_yaffles.acts_as_yaffle.rb")
assert_match /4_create_yaffles/, output
assert File.exists?("#{app_path}/db/migrate/4_create_yaffles.rb")
assert_match /WARNING: Migration 3_create_sessions.rb from bukkits has been skipped/, output
assert_match /Copied migration 4_create_yaffles.rb from acts_as_yaffle/, output
assert_no_match /2_create_users/, output
migrations_count = Dir["#{app_path}/db/migrate/*.rb"].length
output = `rake railties:copy_migrations`
output = `rake railties:install:migrations 2>&1`
assert_equal migrations_count, Dir["#{app_path}/db/migrate/*.rb"].length
assert_match /No migrations were copied/, output
end
end