aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/migration.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/migration.rb')
-rw-r--r--activerecord/lib/active_record/migration.rb69
1 files changed, 41 insertions, 28 deletions
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index e708b3fbcf..a4c09b654a 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -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,9 +428,16 @@ module ActiveRecord
# MigrationProxy is used to defer loading of the actual migration classes
# until they are needed
- class MigrationProxy
+ class MigrationProxy < Struct.new(:name, :version, :filename)
+
+ def initialize(name, version, filename)
+ super
+ @migration = nil
+ end
- attr_accessor :name, :version, :filename, :scope
+ def basename
+ File.basename(filename)
+ end
delegate :migrate, :announce, :write, :to=>:migration
@@ -504,26 +520,21 @@ module ActiveRecord
def migrations(path)
files = Dir["#{path}/[0-9]*_*.rb"]
- migrations = files.inject([]) do |klasses, file|
- version, name, scope = file.scan(/([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?.rb/).first
+ seen = Hash.new false
+
+ migrations = files.map do |file|
+ version, name = file.scan(/([0-9]+)_([_a-z0-9]*).rb/).first
raise IllegalMigrationNameError.new(file) unless version
version = version.to_i
+ name = name.camelize
- if klasses.detect { |m| m.version == version }
- raise DuplicateMigrationVersionError.new(version)
- end
+ raise DuplicateMigrationVersionError.new(version) if seen[version]
+ raise DuplicateMigrationNameError.new(name) if seen[name]
- if klasses.detect { |m| m.name == name.camelize && m.scope == scope }
- raise DuplicateMigrationNameError.new(name.camelize)
- end
+ seen[version] = seen[name] = true
- migration = MigrationProxy.new
- migration.name = name.camelize
- migration.version = version
- migration.filename = file
- migration.scope = scope
- klasses << migration
+ MigrationProxy.new(name, version, file)
end
migrations.sort_by(&:version)
@@ -570,7 +581,7 @@ module ActiveRecord
current = migrations.detect { |m| m.version == current_version }
target = migrations.detect { |m| m.version == @target_version }
- if target.nil? && !@target_version.nil? && @target_version > 0
+ if target.nil? && @target_version && @target_version > 0
raise UnknownMigrationVersionError.new(@target_version)
end
@@ -579,16 +590,18 @@ module ActiveRecord
runnable = migrations[start..finish]
# skip the last migration if we're headed down, but not ALL the way down
- runnable.pop if down? && !target.nil?
+ runnable.pop if down? && target
runnable.each do |migration|
Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
+ seen = migrated.include?(migration.version.to_i)
+
# On our way up, we skip migrating the ones we've already migrated
- next if up? && migrated.include?(migration.version.to_i)
+ next if up? && seen
# On our way down, we skip reverting the ones we've never migrated
- if down? && !migrated.include?(migration.version.to_i)
+ if down? && !seen
migration.announce 'never migrated, skipping'; migration.write
next
end