data_migrator 1.7 → 1.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,73 +1,101 @@
1
1
  require "benchmark"
2
+ require 'extensions/railties/engine'
3
+ require 'extensions/railties/engine/configuration'
2
4
 
3
5
  class DataMigrationTask < Rails::Railtie
4
6
  rake_tasks do
5
- Dir[File.join(File.dirname(__FILE__),'tasks/*.rake')].each { |f| load f }
7
+ Dir[File.join(File.dirname(__FILE__), 'tasks/*.rake')].each { |f| load f }
6
8
  end
7
9
  end
8
10
 
9
11
  module RussellEdge
10
12
  class DataMigrator
11
13
  REMOVE_FILES_REGEX = /^\./
12
-
14
+
13
15
  class << self
16
+ def migrations_path
17
+ "#{Rails.root}/db/data_migrations/"
18
+ end
19
+
20
+ def migrations(path)
21
+ files = Dir["#{path}/**/[0-9]*_*.rb" ]
22
+
23
+ seen = Hash.new false
24
+
25
+ migrations = files.map do |file|
26
+ version, name = file.scan(/([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?.rb/).first
27
+
28
+ raise ActiveRecord::IllegalMigrationNameError.new(file) unless version
29
+ version = version.to_i
30
+ name = name.camelize
31
+
32
+ raise ActiveRecord::DuplicateMigrationVersionError.new(version) if seen[version]
33
+ raise ActiveRecord::DuplicateMigrationNameError.new(name) if seen[name]
34
+
35
+ seen[version] = seen[name] = true
36
+
37
+ {:name => File.basename(file), :filename => file, :version => version}
38
+ end
39
+
40
+ migrations.sort{|h| h[:version]}
41
+ end
42
+
14
43
  def next_migration_number
15
- Time.now.utc.strftime("%Y%m%d%H%M%S")
44
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
16
45
  end
17
-
46
+
18
47
  def initialize_data_migrations_table
19
48
  puts "** data_migrations table missing creating now...."
20
- puts ActiveRecord::Migrator.run(:up, File.join(File.dirname(__FILE__),'../db/migrate/'), 20100819181805)
49
+ puts ActiveRecord::Migrator.run(:up, File.join(File.dirname(__FILE__), '../db/migrate/'), 20100819181805)
21
50
  puts "** done"
22
51
  end
23
-
24
- def prepare_migrations
25
- target = "#{Rails.root}/db/data_migrations/"
26
52
 
27
- # first copy all app data_migrations away
28
- files = Dir["#{target}*.rb"]
53
+ def copy(destination, sources, options = {})
54
+ copied = []
29
55
 
30
- unless files.empty?
31
- FileUtils.mkdir_p "#{target}/ignore/app/"
32
- FileUtils.cp files, "#{target}/ignore/app/"
33
- puts "copied #{files.size} data_migrations to db/data_migrations/ignore/app"
34
- end
56
+ FileUtils.mkdir_p(destination) unless File.exists?(destination)
35
57
 
36
- dirs = Rails::Application::Railties.engines.map{|p| p.config.root.to_s}
37
- files = Dir["{#{dirs.join(',')}}/db/data_migrations/*.rb"]
58
+ destination_migrations = migrations(destination)
59
+ last = destination_migrations.last
60
+ sources.each do |scope, path|
61
+ source_migrations = migrations(path)
38
62
 
39
- unless files.empty?
40
- FileUtils.mkdir_p target
41
- FileUtils.cp files, target
42
- puts "copied #{files.size} migrations to db/data_migrations"
43
- end
44
- end
63
+ source_migrations.each do |migration|
45
64
 
46
- def cleanup_migrations
47
- target = "#{Rails.root}/db/data_migrations/"
65
+ source = File.read(migration[:filename])
66
+ source = "# This migration comes from #{scope} (originally #{migration[:version]})\n#{source}"
48
67
 
49
- files = Dir["#{target}*.rb"]
50
- unless files.empty?
51
- FileUtils.rm files
52
- puts "removed #{files.size} data_migrations from db/data_migrations"
53
- end
54
- files = Dir["#{target}/ignore/app/*.rb"]
55
- unless files.empty?
56
- FileUtils.cp files, target
57
- puts "copied #{files.size} data_migrations back to db/data_migrations"
68
+ if duplicate = destination_migrations.detect { |m| m[:name] == migration[:name] }
69
+ if options[:on_skip] && duplicate.scope != scope.to_s
70
+ options[:on_skip].call(scope, migration)
71
+ end
72
+ next
73
+ end
74
+
75
+ migration[:version] = next_migration_number().to_i
76
+ new_path = File.join(destination, "#{File.basename(migration[:filename], '.*')}.#{scope}.rb")
77
+ old_path, migration[:filename] = migration[:filename], new_path
78
+
79
+ File.open(migration[:filename], "w") { |f| f.write source }
80
+ copied << migration
81
+ options[:on_copy].call(scope, migration, old_path) if options[:on_copy]
82
+ destination_migrations << migration
83
+ end
58
84
  end
59
- FileUtils.rm_rf "#{target}/ignore/app"
85
+
86
+ copied
60
87
  end
88
+
61
89
  end
62
-
90
+
63
91
  def initialize(migrations_path=nil)
64
92
  @default_migrations_path = migrations_path || "#{Rails.root}/db/data_migrations"
65
93
  end
66
-
94
+
67
95
  def migrate(passed_location=nil, passed_version=nil)
68
96
  setup
69
-
70
- location = passed_location.nil? ? @default_migrations_path : passed_location
97
+
98
+ location = passed_location.nil? ? @default_migrations_path : passed_location
71
99
  @@current_version = get_current_version
72
100
 
73
101
  if passed_version.nil? || @@current_version.nil?
@@ -78,12 +106,12 @@ module RussellEdge
78
106
  handle_higher_passed_version(passed_version)
79
107
  end
80
108
  end
81
-
109
+
82
110
  def pending_migrations
83
111
  versions = []
84
112
  files = get_all_files
85
113
  files.each do |file|
86
- filename, version, klass_name = seperate_file_parts(file)
114
+ filename, version, klass_name = separate_file_parts(file)
87
115
  versions << filename unless version_has_been_migrated?(version)
88
116
  end
89
117
 
@@ -99,64 +127,64 @@ module RussellEdge
99
127
 
100
128
  current_version
101
129
  end
102
-
130
+
103
131
  def run_up(passed_version)
104
132
  setup
105
-
133
+
106
134
  raise "VERSION is required" unless passed_version
107
-
135
+
108
136
  files = get_all_files
109
137
  found = false
110
-
138
+
111
139
  files.each do |file|
112
- filename, version, klass_name = seperate_file_parts(file)
140
+ filename, version, klass_name = separate_file_parts(file)
113
141
  if passed_version == version
114
142
  found = true
115
143
  (version_has_been_migrated?(version)) ? (puts "** Version #{passed_version} has already been migrated") : handle_action(file, klass_name, version, :up)
116
144
  end
117
145
  end
118
-
146
+
119
147
  puts "** Version #{passed_version} not found" unless found
120
-
148
+
121
149
  end
122
-
150
+
123
151
  def run_down(passed_version)
124
152
  setup
125
-
153
+
126
154
  raise "VERSION is required" unless passed_version
127
-
155
+
128
156
  files = get_all_files
129
- found = false
157
+ found = false
130
158
 
131
159
  files.each do |file|
132
- filename, version, klass_name = seperate_file_parts(file)
160
+ filename, version, klass_name = separate_file_parts(file)
133
161
  if passed_version == version
134
162
  found = true
135
163
  (version_has_been_migrated?(version)) ? handle_action(file, klass_name, version, :down) : (puts "** Version #{passed_version} has not been migrated")
136
164
  end
137
165
  end
138
-
166
+
139
167
  puts "** Version #{passed_version} not found" unless found
140
-
168
+
141
169
  end
142
-
170
+
143
171
  private
144
-
172
+
145
173
  def setup
146
174
  RussellEdge::DataMigrator.initialize_data_migrations_table unless data_migrations_table_exists?
147
-
148
- unless File.directory? @default_migrations_path
149
- FileUtils.mkdir_p( @default_migrations_path)
175
+
176
+ unless File.directory? @default_migrations_path
177
+ FileUtils.mkdir_p(@default_migrations_path)
150
178
  #create ignore folder
151
- FileUtils.mkdir_p(File.join(@default_migrations_path,'ignore/'))
179
+ FileUtils.mkdir_p(File.join(@default_migrations_path, 'ignore/'))
152
180
  end
153
181
  end
154
-
182
+
155
183
  def handle_higher_passed_version(passed_version)
156
184
  files = get_all_files
157
185
 
158
186
  files.each do |file|
159
- filename, version, klass_name = seperate_file_parts(file)
187
+ filename, version, klass_name = separate_file_parts(file)
160
188
  if version <= passed_version
161
189
  unless version_has_been_migrated?(version)
162
190
  handle_action(file, klass_name, version, :up)
@@ -170,9 +198,9 @@ module RussellEdge
170
198
  files = get_all_files
171
199
 
172
200
  files.each do |file|
173
- filename, version, klass_name = seperate_file_parts(file)
201
+ filename, version, klass_name = separate_file_parts(file)
174
202
  if passed_version.nil? or version <= passed_version
175
- if !version_has_been_migrated?(version)
203
+ if !version_has_been_migrated?(version)
176
204
  handle_action(file, klass_name, version, :up)
177
205
  end
178
206
  end
@@ -183,7 +211,7 @@ module RussellEdge
183
211
  files = get_all_files
184
212
 
185
213
  files.each do |file|
186
- filename, version, klass_name = seperate_file_parts(file)
214
+ filename, version, klass_name = separate_file_parts(file)
187
215
  if version > passed_version
188
216
  handle_action(file, klass_name, version, :down) if version_has_been_migrated?(version)
189
217
  end
@@ -201,16 +229,15 @@ module RussellEdge
201
229
  klass.send(action.to_s)
202
230
  end
203
231
  end
204
- rescue Exception=>ex
205
- RussellEdge::DataMigrator.cleanup_migrations
232
+ rescue Exception => ex
206
233
  raise ex
207
234
  end
208
235
  time_str = "(%.4fs)" % time.real
209
236
  puts "================Finished #{klass.to_s} in #{time_str}=="
210
-
237
+
211
238
  (action == :up) ? insert_migration_version(version) : remove_migration_version(version)
212
239
  end
213
-
240
+
214
241
  def insert_migration_version(version)
215
242
  ActiveRecord::Base.connection.execute("insert into data_migrations (version) values ('#{version}')")
216
243
  end
@@ -225,42 +252,43 @@ module RussellEdge
225
252
  db_result = ActiveRecord::Base.connection.select_all("select count(*) as num_rows from data_migrations where version = '#{version}'")
226
253
 
227
254
  num_rows = db_result[0]['num_rows'] unless db_result == -1
228
-
255
+
229
256
  result = false if (num_rows.nil? || num_rows.to_i == 0)
230
257
  result
231
258
  end
232
259
 
233
260
  def data_migrations_table_exists?
234
- table_names = ActiveRecord::Base.connection.tables
261
+ table_names = ActiveRecord::Base.connection.tables
235
262
  table_names.include?('data_migrations')
236
263
  end
237
264
 
238
- def seperate_file_parts(file)
265
+ def separate_file_parts(file)
239
266
  paths = file.split('/')
240
267
  filename = paths[paths.length - 1]
241
268
  version = filename.split('_')[0]
242
269
  klass_name = filename.gsub(/#{version}/, "").gsub(/.rb/, "")[1..filename.length]
270
+ klass_name = klass_name.split('.')[0] if klass_name.split('.').length > 1 #check for scope of engine name
243
271
 
244
272
  return filename, version.to_i, klass_name
245
273
  end
246
274
 
247
275
  def get_all_files
248
276
  files = []
249
-
277
+
250
278
  if File.directory? @default_migrations_path
251
-
252
- files_or_directories = Dir.entries(@default_migrations_path).map{|directory| directory}
253
279
 
254
- files_or_directories.delete_if{|name| name =~ REMOVE_FILES_REGEX} #remove any file leading with . or ..
255
- files_or_directories.delete_if{|name| name == 'ignore'} #ignore the ignore folder
280
+ files_or_directories = Dir.entries(@default_migrations_path).map { |directory| directory }
281
+
282
+ files_or_directories.delete_if { |name| name =~ REMOVE_FILES_REGEX } #remove any file leading with . or ..
283
+ files_or_directories.delete_if { |name| name == 'ignore' } #ignore the ignore folder
284
+
256
285
 
257
-
258
286
  files_or_directories.each do |file_or_directory|
259
287
  file_or_directory = @default_migrations_path + "/" + file_or_directory
260
288
  files = get_files_in_directory(file_or_directory, files)
261
289
  end
262
290
 
263
- files.sort! {|x,y| File.basename(x) <=> File.basename(y)}
291
+ files.sort! { |x, y| File.basename(x) <=> File.basename(y) }
264
292
  end
265
293
 
266
294
  files
@@ -268,10 +296,10 @@ module RussellEdge
268
296
 
269
297
  def get_files_in_directory(file_or_directory, files)
270
298
  unless file_or_directory =~ /\w\.rb/
271
- files_or_directories = Dir.entries(file_or_directory).map{|directory| directory}
299
+ files_or_directories = Dir.entries(file_or_directory).map { |directory| directory }
272
300
 
273
- files_or_directories.delete_if{|name| name =~ REMOVE_FILES_REGEX} #remove any file leading with . or ..
274
- files_or_directories.delete_if{|name| name == 'ignore'} #ignore the ignore folder
301
+ files_or_directories.delete_if { |name| name =~ REMOVE_FILES_REGEX } #remove any file leading with . or ..
302
+ files_or_directories.delete_if { |name| name == 'ignore' } #ignore the ignore folder
275
303
 
276
304
  files_or_directories.each do |_file_or_directory|
277
305
  _file_or_directory = file_or_directory + "/" + _file_or_directory
@@ -0,0 +1,23 @@
1
+ Rails::Engine.class_eval do
2
+ rake_tasks do
3
+ next if self.is_a?(Rails::Application)
4
+ next unless has_data_migrations?
5
+
6
+ namespace railtie_name do
7
+ namespace :install do
8
+ desc "Copy data_migrations from #{railtie_name} to application"
9
+ task :data_migrations do
10
+ ENV["FROM"] = railtie_name
11
+ Rake::Task["railties:install:data_migrations"].invoke
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ protected
18
+
19
+ def has_data_migrations?
20
+ paths["db/data_migrations"].existent.any?
21
+ end
22
+
23
+ end
@@ -0,0 +1,30 @@
1
+ Rails::Engine::Configuration.class_eval do
2
+ def paths
3
+ @paths ||= begin
4
+ paths = Rails::Paths::Root.new(@root)
5
+ paths.add "app", :eager_load => true, :glob => "*"
6
+ paths.add "app/assets", :glob => "*"
7
+ paths.add "app/controllers", :eager_load => true
8
+ paths.add "app/helpers", :eager_load => true
9
+ paths.add "app/models", :eager_load => true
10
+ paths.add "app/mailers", :eager_load => true
11
+ paths.add "app/views"
12
+ paths.add "lib", :load_path => true
13
+ paths.add "lib/assets", :glob => "*"
14
+ paths.add "lib/tasks", :glob => "**/*.rake"
15
+ paths.add "config"
16
+ paths.add "config/environments", :glob => "#{Rails.env}.rb"
17
+ paths.add "config/initializers", :glob => "**/*.rb"
18
+ paths.add "config/locales", :glob => "*.{rb,yml}"
19
+ paths.add "config/routes", :with => "config/routes.rb"
20
+ paths.add "db"
21
+ paths.add "db/migrate"
22
+ paths.add "db/data_migrations"
23
+ paths.add "db/seeds", :with => "db/seeds.rb"
24
+ paths.add "vendor", :load_path => true
25
+ paths.add "vendor/assets", :glob => "*"
26
+ paths.add "vendor/plugins"
27
+ paths
28
+ end
29
+ end
30
+ end
@@ -2,20 +2,16 @@ namespace :db do
2
2
  desc 'migrates data into database'
3
3
  task :migrate_data => :environment do
4
4
  passed_version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
5
- RussellEdge::DataMigrator.prepare_migrations
5
+
6
6
  RussellEdge::DataMigrator.new.migrate(nil, passed_version)
7
- RussellEdge::DataMigrator.cleanup_migrations
8
-
9
7
  end#end migrate_data task
10
8
 
11
9
  namespace :migrate_data do
12
10
  task :list_pending => :environment do
13
- RussellEdge::DataMigrator.prepare_migrations
14
11
  pending_migrations = RussellEdge::DataMigrator.new.pending_migrations
15
12
  puts "================Pending Data Migrations=========="
16
13
  puts pending_migrations
17
14
  puts "================================================="
18
- RussellEdge::DataMigrator.cleanup_migrations
19
15
  end#end list_pending task
20
16
 
21
17
  task :version => :environment do
@@ -26,23 +22,44 @@ namespace :db do
26
22
  task :up => :environment do
27
23
  passed_version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
28
24
  raise "VERSION is required" unless passed_version
29
-
30
- RussellEdge::DataMigrator.prepare_migrations
25
+
31
26
  RussellEdge::DataMigrator.new.run_up(passed_version)
32
- RussellEdge::DataMigrator.cleanup_migrations
33
-
34
27
  end#end up task
35
28
 
36
29
  task :down => :environment do
37
30
  passed_version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
38
31
  raise "VERSION is required" unless passed_version
39
-
40
- RussellEdge::DataMigrator.prepare_migrations
32
+
41
33
  RussellEdge::DataMigrator.new.run_down(passed_version)
42
- RussellEdge::DataMigrator.cleanup_migrations
43
-
44
34
  end#end down task
45
35
  end#end namespace
46
36
  end
47
37
 
38
+ namespace :railties do
39
+ namespace :install do
40
+ # desc "Copies missing data_migrations from Railties (e.g. plugins, engines). You can specify Railties to use with FROM=railtie1,railtie2"
41
+ task :data_migrations => :environment do
42
+ to_load = ENV['FROM'].blank? ? :all : ENV['FROM'].split(",").map {|n| n.strip }
43
+ railties = ActiveSupport::OrderedHash.new
44
+ Rails.application.railties.all do |railtie|
45
+ next unless to_load == :all || to_load.include?(railtie.railtie_name)
46
+
47
+ if railtie.respond_to?(:paths) && (path = railtie.paths['db/data_migrations'].first)
48
+ railties[railtie.railtie_name] = path
49
+ end
50
+ end
51
+
52
+ on_skip = Proc.new do |name, migration|
53
+ puts "NOTE: Data Migration #{migration[:name]} from #{name} has been skipped. Migration with the same name already exists."
54
+ end
55
+
56
+ on_copy = Proc.new do |name, migration, old_path|
57
+ puts "Copied data_migration #{migration[:name]} from #{name}"
58
+ end
59
+
60
+ RussellEdge::DataMigrator.copy(RussellEdge::DataMigrator.migrations_path, railties, :on_skip => on_skip, :on_copy => on_copy)
61
+ end
62
+ end
63
+ end
64
+
48
65
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: data_migrator
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.7'
4
+ version: '1.8'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,19 +9,19 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-09-26 00:00:00.000000000Z
12
+ date: 2012-10-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: activerecord
16
- requirement: &2157691620 !ruby/object:Gem::Requirement
15
+ name: rails
16
+ requirement: &70230211897860 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
20
20
  - !ruby/object:Gem::Version
21
- version: 2.3.5
21
+ version: '2.3'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2157691620
24
+ version_requirements: *70230211897860
25
25
  description: Allows you to create data migrations that can be run up and down to insert
26
26
  data into the database.
27
27
  email: russellfholmes@gmail.com
@@ -31,6 +31,8 @@ extra_rdoc_files: []
31
31
  files:
32
32
  - db/migrate/20100819181805_create_data_migrations_table.rb
33
33
  - lib/data_migrator.rb
34
+ - lib/extensions/railties/engine/configuration.rb
35
+ - lib/extensions/railties/engine.rb
34
36
  - lib/generators/data_migration/data_migration_generator.rb
35
37
  - lib/generators/data_migration/templates/migration_template.rb
36
38
  - lib/generators/data_migration/USAGE
@@ -59,7 +61,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
59
61
  version: '0'
60
62
  requirements: []
61
63
  rubyforge_project:
62
- rubygems_version: 1.8.6
64
+ rubygems_version: 1.8.11
63
65
  signing_key:
64
66
  specification_version: 3
65
67
  summary: Creates Data Migrations for data similar to schema migrations.