# frozen_string_literal: true # License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later # from https://coderwall.com/p/ijr6jq/rake-progress-bar class ProgressBar attr_reader :total, :counter def initialize(total, description) @description = description @total = total @counter = 1 end def increment print_out @counter += 1 end def print_out complete = sprintf("%#.2f%%", ((@counter.to_f / @total.to_f) * 100)) print "\r\e[0K#{@description} #{@counter}/#{@total} (#{complete})" end def increment_total(by_amount) @total += by_amount print_out end end namespace :houdini_upgrade do Rake::Task["install:migrations"].clear_comments desc <<-RUBY Run houdini upgrade to v2 DESC: This task automates some of the process of upgrading to Houdini v2. It does the following: * installs and runs database migrations * migrates images from Carrierwave on AWS to your default ActiveStorage service USAGE: bin/rails houdini_upgrade:run[aws_bucket,aws_region] TASK ARGUMENTS: aws_bucket (required): the name of your AWS bucket where all your carrierwave images are hosted aws_region (required): AWS region of your AWS bucket. Carrierwave won\'t work without it. aws_assethost: protocol and domain where your AWS bucket contents can be accessed. For example, this could be through Cloudfront shorter_test: a testing only argument which cuts down the number of images we copy RUBY task :run, [:aws_bucket, :aws_region, :aws_assethost, :shorter_test] do |t, args| if args[:aws_bucket].blank? || args[:aws_region].blank? puts "You must set aws_bucket and aws_region for houdini_upgrade:run like:" puts " houdini_upgrade:run[aws_bucket,aws_region]" puts "" puts "See the full task description by running `bin/rails -D` or " puts "visit `docs/houdini_upgrade.md`" else Rake::Task["houdini_upgrade:install:migrations"].invoke Rake::Task["active_storage:install"].invoke Rake::Task["houdini_upgrade:cw_to_activestorage"].invoke(*args) sh 'bundle' Rake::Task["db:migrate"].invoke migrate_upload_command = "rails houdini_upgrade:migrate_uploads" if args[:shorter_test] migrate_upload_command += "[true]" end sh migrate_upload_command Rake::Task["houdini_upgrade:create_backup_uploader_migration"].invoke sh "rails db:migrate" Rake::Task["houdini_upgrade:cleanup_upgrade_files"].invoke sh 'bundle' end end task :cw_to_activestorage, [:aws_bucket, :aws_region, :aws_assethost] do |t, args| tail = ["--aws-bucket=#{args[:aws_bucket]}", "--aws-region=#{args[:aws_region]}"] tail.push("--aws-assethost=#{args[:aws_assethost]}") if args[:aws_assethost] sh "rails generate cw_to_activestorage #{tail.join(' ')}" end desc "Migrate your CarrierWave uploads to activestorage" task :migrate_uploads, [:shorter_test] => [:environment] do |t, args| progress_bar = ProgressBar.new(0, "Upload migration progress") results = [] Rails.application.eager_load! # find activerecord descendents HoudiniUpgrade::UPLOADERS_TO_MIGRATE.each do |table| klass = table.class_name.constantize items_to_migrate = klass.where(table.fields.map{|i| i.migrated_name + " IS NOT NULL"}.join(" OR ")) if args[:shorter_test] items_to_migrate = items_to_migrate.limit(10) end progress_bar.increment_total(items_to_migrate.count * table.fields.count) items_to_migrate .find_each do |record| table.fields.each do |field| if record.send(field.migrated_name + "?") results << process(upload_url: record.send(field.migrated_name).url.gsub(/\/#{field.migrated_name}\//, "/#{field.name}/"), attachment_name: field.name, record: record) end progress_bar.increment end end end copied = results.select{|i| i[:success]}.map{|i| i[:value]} errors = results.select{|i| !i[:success]}.map{|i| i[:value]} CSV.open("#{DateTime.now.utc.strftime('%Y%m%d%H%M%S')}_copied.csv", 'wb') do |csv| csv << ['Name', 'Id', "UploaderName", "FileToOpen", "CodeToRun"] copied.each {|row| csv << row} end CSV.open("#{DateTime.now.utc.strftime('%Y%m%d%H%M%S')}_errored.csv", 'wb') do |csv| csv << ['Name', 'Id', "UploaderName", "Error"] errors.each {|row| csv << row} end puts "Copied: #{copied.count}" puts "Errored: #{errors.count}" end def process(**args) begin if args[:upload_url] filename = File.basename(URI.parse(args[:upload_url]).to_s) file_to_open = args[:upload_url].start_with?('/') ? "." + args[:upload_url] : args[:upload_url] if (!args[:simulate]) attachment_relation = args[:record].send("#{args[:attachment_name].to_s}") attachment_relation.attach(io: open(file_to_open), filename: filename) end return {success: true, value: [args[:record].id,args[:attachment_name],file_to_open]} end return nil rescue => e return {success: false, value: [ args[:record].id, args[:attachment_name], e]} end end task :create_backup_uploader_migration do if (Dir.glob("db/migrate/*_backup_uploader_columns.houdini_upgrade.rb").none?) FileUtils.cp __dir__ + "/templates/backup_uploader_columns.rb", "db/migrate/#{(DateTime.now.utc + 1.second).strftime('%Y%m%d%H%M%S')}_backup_uploader_columns.houdini_upgrade.rb" end end task :delete_uploader_backup_tables_migration do if (Dir.glob("db/migrate/*_backup_uploader_columns.houdini_upgrade.rb").none?) FileUtils.cp __dir + "/templates/delete_uploader_backup_tables.rb", "db/migrate/#{(DateTime.now.utc + 1.second).strftime('%Y%m%d%H%M%S')}_delete_uploader_backup_tables.houdini_upgrade.rb" end end task :cleanup_upgrade_files do FileUtils.rm_r "app/uploaders" if (File.exists?("app/uploaders")) FileUtils.rm "config/initializers/carrierwave.rb" if (File.exists?("config/initializers/carrierwave.rb")) gemfile_lines = File.readlines("Gemfile").select{|i| !i.include?("gem 'carrierwave'") && !i.include?("gem 'carrierwave-aws'")} File.write('Gemfile', gemfile_lines.join()) cleanup_model_files end def cleanup_model_files filename_roots = HoudiniUpgrade::UPLOADERS_TO_MIGRATE.map{|i| i.name.singularize} filename_roots.each do |f| filename = "app/models/#{f}.rb" file_contents = File.read(filename) file_contents = file_contents.sub(/\#\#\#MIGRATION_FIELDS_BEGIN(.*)\#\#\#MIGRATION_FIELDS_END/mx, '') File.write(filename, file_contents) end end end