140 lines
4.1 KiB
Ruby
140 lines
4.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Gitlab
|
|
module BackgroundMigration
|
|
# This class takes a legacy upload and migrates it to the correct location
|
|
class LegacyUploadMover
|
|
include Gitlab::Utils::StrongMemoize
|
|
|
|
attr_reader :upload, :project, :note
|
|
attr_accessor :logger
|
|
|
|
def initialize(upload)
|
|
@upload = upload
|
|
@note = Note.find_by(id: upload.model_id)
|
|
@project = note&.project
|
|
@logger = Gitlab::BackgroundMigration::Logger.build
|
|
end
|
|
|
|
def execute
|
|
return unless upload
|
|
|
|
if !project
|
|
# if we don't have models associated with the upload we can not move it
|
|
warn('Deleting upload due to model not found.')
|
|
|
|
destroy_legacy_upload
|
|
elsif note.is_a?(LegacyDiffNote)
|
|
return unless move_legacy_diff_file
|
|
|
|
migrate_upload
|
|
elsif !legacy_file_exists?
|
|
warn('Deleting upload due to file not found.')
|
|
destroy_legacy_upload
|
|
else
|
|
migrate_upload
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def migrate_upload
|
|
return unless copy_upload_to_project
|
|
|
|
add_upload_link_to_note_text
|
|
destroy_legacy_file
|
|
destroy_legacy_upload
|
|
end
|
|
|
|
# we should proceed and log whenever one upload copy fails, no matter the reasons
|
|
# rubocop: disable Lint/RescueException
|
|
def copy_upload_to_project
|
|
@uploader = FileUploader.copy_to(legacy_file_uploader, project)
|
|
|
|
logger.info(
|
|
message: 'MigrateLegacyUploads: File copied successfully',
|
|
old_path: legacy_file_uploader.file.path, new_path: @uploader.file.path
|
|
)
|
|
true
|
|
rescue Exception => e
|
|
warn(
|
|
'File could not be copied to project uploads',
|
|
file_path: legacy_file_uploader.file.path, error: e.message
|
|
)
|
|
false
|
|
end
|
|
# rubocop: enable Lint/RescueException
|
|
|
|
def destroy_legacy_upload
|
|
if note
|
|
note.remove_attachment = true
|
|
note.save
|
|
end
|
|
|
|
if upload.destroy
|
|
logger.info(message: 'MigrateLegacyUploads: Upload was destroyed.', upload: upload.inspect)
|
|
else
|
|
warn('MigrateLegacyUploads: Upload destroy failed.')
|
|
end
|
|
end
|
|
|
|
def destroy_legacy_file
|
|
legacy_file_uploader.file.delete
|
|
end
|
|
|
|
def add_upload_link_to_note_text
|
|
new_text = "#{note.note} \n #{@uploader.markdown_link}"
|
|
# Bypass validations because old data may have invalid
|
|
# noteable values. If we fail hard here, we may kill the
|
|
# entire background migration, which affects a range of notes.
|
|
note.update_attribute(:note, new_text)
|
|
end
|
|
|
|
def legacy_file_uploader
|
|
strong_memoize(:legacy_file_uploader) do
|
|
uploader = upload.build_uploader
|
|
uploader.retrieve_from_store!(File.basename(upload.path))
|
|
uploader
|
|
end
|
|
end
|
|
|
|
def legacy_file_exists?
|
|
legacy_file_uploader.file.exists?
|
|
end
|
|
|
|
# we should proceed and log whenever one upload copy fails, no matter the reasons
|
|
# rubocop: disable Lint/RescueException
|
|
def move_legacy_diff_file
|
|
old_path = upload.absolute_path
|
|
old_path_sub = '-/system/note/attachment'
|
|
|
|
if !File.exist?(old_path) || !old_path.include?(old_path_sub)
|
|
log_legacy_diff_note_problem(old_path)
|
|
return false
|
|
end
|
|
|
|
new_path = upload.absolute_path.sub(old_path_sub, '-/system/legacy_diff_note/attachment')
|
|
new_dir = File.dirname(new_path)
|
|
FileUtils.mkdir_p(new_dir)
|
|
|
|
FileUtils.mv(old_path, new_path)
|
|
rescue Exception => e
|
|
log_legacy_diff_note_problem(old_path, new_path, e)
|
|
false
|
|
end
|
|
|
|
def warn(message, params = {})
|
|
logger.warn(
|
|
params.merge(message: "MigrateLegacyUploads: #{message}", upload: upload.inspect)
|
|
)
|
|
end
|
|
|
|
def log_legacy_diff_note_problem(old_path, new_path = nil, error = nil)
|
|
warn('LegacyDiffNote upload could not be moved to a new path',
|
|
old_path: old_path, new_path: new_path, error: error&.message
|
|
)
|
|
end
|
|
# rubocop: enable Lint/RescueException
|
|
end
|
|
end
|
|
end
|