diff options
Diffstat (limited to 'app/services/bulk_imports/relation_export_service.rb')
-rw-r--r-- | app/services/bulk_imports/relation_export_service.rb | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/app/services/bulk_imports/relation_export_service.rb b/app/services/bulk_imports/relation_export_service.rb new file mode 100644 index 00000000000..53952a33b5f --- /dev/null +++ b/app/services/bulk_imports/relation_export_service.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +module BulkImports + class RelationExportService + include Gitlab::ImportExport::CommandLineUtil + + def initialize(user, portable, relation, jid) + @user = user + @portable = portable + @relation = relation + @jid = jid + end + + def execute + find_or_create_export! do |export| + remove_existing_export_file!(export) + serialize_relation_to_file(export.relation_definition) + compress_exported_relation + upload_compressed_file(export) + end + end + + private + + attr_reader :user, :portable, :relation, :jid + + def find_or_create_export! + validate_user_permissions! + + export = portable.bulk_import_exports.safe_find_or_create_by!(relation: relation) + export.update!(status_event: 'start', jid: jid) + + yield export + + export.update!(status_event: 'finish', error: nil) + rescue StandardError => e + Gitlab::ErrorTracking.track_exception(e, portable_id: portable.id, portable_type: portable.class.name) + + export&.update(status_event: 'fail_op', error: e.class) + end + + def validate_user_permissions! + ability = "admin_#{portable.to_ability_name}" + + user.can?(ability, portable) || + raise(::Gitlab::ImportExport::Error.permission_error(user, portable)) + end + + def remove_existing_export_file!(export) + upload = export.upload + + return unless upload&.export_file&.file + + upload.remove_export_file! + upload.save! + end + + def serialize_relation_to_file(relation_definition) + serializer.serialize_relation(relation_definition) + end + + def compress_exported_relation + gzip(dir: export_path, filename: ndjson_filename) + end + + def upload_compressed_file(export) + compressed_filename = File.join(export_path, "#{ndjson_filename}.gz") + upload = ExportUpload.find_or_initialize_by(export_id: export.id) # rubocop: disable CodeReuse/ActiveRecord + + File.open(compressed_filename) { |file| upload.export_file = file } + + upload.save! + end + + def config + @config ||= FileTransfer.config_for(portable) + end + + def export_path + @export_path ||= config.export_path + end + + def portable_tree + @portable_tree ||= config.portable_tree + end + + # rubocop: disable CodeReuse/Serializer + def serializer + @serializer ||= ::Gitlab::ImportExport::JSON::StreamingSerializer.new( + portable, + portable_tree, + json_writer, + exportable_path: '' + ) + end + # rubocop: enable CodeReuse/Serializer + + def json_writer + @json_writer ||= ::Gitlab::ImportExport::JSON::NdjsonWriter.new(export_path) + end + + def ndjson_filename + @ndjson_filename ||= "#{relation}.ndjson" + end + end +end |