FEATURE: new 'uploads:migrate_to_new_pattern' rake task

This commit is contained in:
Régis Hanol 2015-05-19 12:31:51 +02:00
parent 9ded21e4c6
commit 5e527178b9
1 changed files with 138 additions and 0 deletions

View File

@ -277,3 +277,141 @@ def regenerate_missing_optimized
missing_uploads.sort.each { |u| puts u }
end
end
task "uploads:migrate_to_new_pattern" => :environment do
ENV["RAILS_DB"] ? migrate_to_new_pattern : migrate_to_new_pattern_all_sites
end
def migrate_to_new_pattern_all_sites
RailsMultisite::ConnectionManagement.each_connection { migrate_to_new_pattern }
end
def migrate_to_new_pattern
db = RailsMultisite::ConnectionManagement.current_db
puts "Migrating uploads to new pattern for '#{db}'..."
migrate_uploads_to_new_pattern
puts "Migrating optimized images to new pattern for '#{db}'..."
migrate_optimized_images_to_new_pattern
puts "Done!"
end
def migrate_uploads_to_new_pattern
if Upload.where(sha1: nil).exists?
puts "Computing missing SHAs..."
Upload.where(sha1: nil).find_each do |upload|
path = Discourse.store.path_for(upload)
size = File.size(path) rescue 0
if size > 0
upload.sha1 = Digest::SHA1.file(path).hexdigest
upload.save
putc "."
else
upload.destroy
putc "X"
end
end
puts
end
puts "Moving uploads to new location..."
Upload.where.not(sha1: nil)
.where("url LIKE '/uploads/%'")
.where("url NOT LIKE '/uploads/%/original/%'")
.find_each do |upload|
path = Discourse.store.path_for(upload)
if File.exists?(path)
file = File.open(path)
# copy file to new location
url = Discourse.store.store_upload(file, upload)
file.try(:close!) rescue nil
# remap URLs
remap(upload.url, url)
# remove old file
FileUtils.rm(path, force: true) rescue nil
putc "."
else
# upload.destroy
putc "X"
end
end
puts
end
def migrate_optimized_images_to_new_pattern
if OptimizedImage.where(sha1: nil).exists?
puts "Computing missing SHAs..."
OptimizedImage.where(sha1: nil).find_each do |optimized_image|
path = Discourse.store.path_for(optimized_image)
size = File.size(path) rescue 0
if size > 0
optimized_image.sha1 = Digest::SHA1.file(path).hexdigest
optimized_image.save
putc "."
else
optimized_image.destroy
putc "X"
end
end
puts
end
puts "Moving optimized images to new location..."
OptimizedImage.where.not(sha1: nil)
.where("width > 0 AND height > 0")
.where("url LIKE '/uploads/%/_optimized/%'")
.where("url NOT LIKE '/uploads/%/optimized/%'")
.find_each do |optimized_image|
path = Discourse.store.path_for(optimized_image)
if File.exists?(path)
file = File.open(path)
# copy file to new location
url = Discourse.store.store_optimized_image(file, optimized_image)
file.try(:close!) rescue nil
# remap URLs
remap(optimized_image.url, url)
# remove old file
FileUtils.rm(path, force: true) rescue nil
putc "."
else
optimized_image.destroy
putc "X"
end
end
puts
end
REMAP_SQL ||= "
SELECT table_name, column_name
FROM information_schema.columns
WHERE table_schema = 'public'
AND is_updatable = 'YES'
AND (data_type LIKE 'char%' OR data_type LIKE 'text%')
ORDER BY table_name, column_name
"
def remap(from, to)
connection ||= ActiveRecord::Base.connection.raw_connection
remappable_columns ||= connection.async_exec(REMAP_SQL).to_a
remappable_columns.each do |rc|
table_name = rc["table_name"]
column_name = rc["column_name"]
begin
connection.async_exec("
UPDATE #{table_name}
SET #{column_name} = REPLACE(#{column_name}, $1, $2)
WHERE #{column_name} IS NOT NULL
AND #{column_name} <> REPLACE(#{column_name}, $1, $2)", [from, to])
rescue
end
end
end