forked from yannlugrin/globalize
-
Notifications
You must be signed in to change notification settings - Fork 1
/
migration_tools.rake
185 lines (152 loc) · 6.23 KB
/
migration_tools.rake
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#Setup migration logger
def setup_logging(path_to_logger)
path_to_logger = path_to_logger
@logger = Logger.new(path_to_logger)
ActiveRecord::Base.logger = @logger
puts "Logging to #{path_to_logger}"
end
def log(msg, level = Logger::DEBUG)
@logger.add(level, msg)
end
#Print to stdout and log message
def print_and_log(message)
puts message
log(message)
end
#Ask the user a question
def ask(question)
puts question
result = STDIN.gets.chomp
[result.empty? || result.match(/[a|A]/),result.match(/[y|Y]/)]
end
#Load a model given its name
def load_model_class(model_file_name)
File.basename(model_file_name).gsub(File.extname(model_file_name),'').camelize.constantize rescue nil
end
#Find all Active::Record models
#TODO: test for nested models
def find_models
models = []
FileList["#{RAILS_ROOT}/app/models/**/*.rb"].sort.each do |fn|
model_class = load_model_class(fn)
models << [model_class,fn] if model_class &&
model_class.respond_to?(:base_class) &&
model_class.base_class.superclass == ActiveRecord::Base
end
models
end
#Find all models which use the external storage system
def find_externally_translated_models(models)
externally_translated_models = []
models.each do |model_data|
model = model_data.first
if (model.respond_to?(:globalize_facets) &&
(!model.globalize_facets.empty?) &&
model.respond_to?(:untranslated_find))
externally_translated_models << model_data
end
end
externally_translated_models
end
#Migrate ruby source to external storage mechanism for the supplied path
def migrate_ruby_source(source_file_name)
print_and_log "Migrating ruby source for: #{source_file_name}"
content = File.read(source_file_name)
#Replace or add declarations
unless content.match(/keep_translations_in_model/)
translates_declaration = content.match(/\s+(translates.*)/)[1]
whitespace = content.match(/(\s+)translates.*/)[1]
line_returns = whitespace.gsub(' ','')
indent = whitespace.gsub(line_returns,'')
indent ||= ' '
content.sub!(/(\s+translates.*)\n/, "#{line_returns}#{indent}self.keep_translations_in_model = true\n#{indent}#{translates_declaration}\n") if translates_declaration
else
content.sub!(/(keep_translations_in_model\s+=\s+false)/, 'keep_translations_in_model = true')
end
# Write it back
File.open(source_file_name, "w") { |f| f.puts content }
end
#Execute globalize generator for internal storage migrations
def generate_db_migrations
print_and_log ("Generating db migrations...")
system("script/generate globalize internal #{ENV['LANGS']}")
end
#Run rake db:migrate
def execute_db_migrations
print_and_log ("Executing db migrations...")
system('rake db:migrate')
end
#Transfer data from internal to external storage system
def migrate_translated_data(model, delete_old_translations = false)
migrated = false
sql = <<-SQL
SELECT distinct(item_id)
FROM globalize_translations
where globalize_translations.type = 'ModelTranslation'
and globalize_translations.table_name = '#{model.table_name}'
SQL
#Find distinct translated model ids
model_instances = model.connection.select_all(sql)
unless model_instances.empty?
model_instances.collect {|r| r['item_id'].to_i}.each do |item_id|
#Find model instance for current model id
model_instance = model.find(item_id)
if model_instance
conditions = {:type => 'ModelTranslation',
:table_name => model.table_name,
:item_id => item_id}
#Find translations in all langs for current model id
translations = Globalize::ModelTranslation.find(:all, :conditions => conditions)
#Update appropriate facets
translations.each do |translation|
facet = translation.facet
lang = Globalize::Language.find(translation.language_id)
model_instance.send("#{facet}_#{lang.iso_639_1}=", translation.text) unless model_instance.send("#{facet}_#{lang.iso_639_1}")
end
begin
model_instance.save!
translations.each {|tr| tr.destroy } if delete_old_translations
migrated = true
rescue Exception => e
log "Unable to migrate translations for model: #{model.name} Exception: #{e.message} Trace: #{e.backtrace.join("\n")}"
end
end
end
else
print_and_log "No translations found in globalize_translations for model: #{model.name}"
end
migrated
end
def migrate_translations(models)
should_migrate_all, should_migrate = false, false
should_delete_old_all, should_delete_old = false, false
models.each do |model_data|
should_migrate_all, should_migrate = ask("Migrate translations for '#{model_data.first.name}'? (Yes/No/All)") unless should_migrate_all
should_delete_old_all, should_delete_old = ask("Also delete old external translations for '#{model_data.first.name}'? (Yes/No default: Y)") unless should_delete_old_all
migrated = migrate_translated_data(load_model_class(model_data.last), should_delete_old_all || should_delete_old ) if should_migrate_all || should_migrate
print_and_log "Migrated translations for #{model_data.first.name}" if migrated
end
end
namespace :globalize do
desc 'Migrate models to internal storage system '
task :migrate_to_internal_storage => :environment do
setup_logging("#{RAILS_ROOT}/log/internal_storage_migration_#{RAILS_ENV}.log")
should_migrate_all, should_migrate = false, false
#Find models to migrate
models_to_migrate = find_externally_translated_models(find_models)
#Migrate ruby source
models_to_migrate.each do |model_data|
should_migrate_all, should_migrate = ask("Migrate source for '#{model_data.first.name}'? (Yes/No/All)") unless should_migrate_all
migrate_ruby_source(model_data.last) if should_migrate_all || should_migrate
end
print_and_log "No source to migrate" unless should_migrate_all || should_migrate
if should_migrate_all || should_migrate
should_migrate_all, should_migrate = ask("Generate & execute db migrations? (Yes/No)")
#generate and execute migrations
if should_migrate_all || should_migrate
execute_db_migrations if generate_db_migrations
migrate_translations(models_to_migrate)
end
end
end
end