# frozen_string_literal: true module BackupRestore MetaDataError = Class.new(RuntimeError) MigrationRequiredError = Class.new(RuntimeError) class MetaDataHandler METADATA_FILE = "meta.json" delegate :log, to: :@logger, private: true def initialize(logger, filename, tmp_directory) @logger = logger @current_version = BackupRestore.current_version @filename = filename @tmp_directory = tmp_directory end def validate metadata = extract_metadata if !metadata[:version].is_a?(Integer) raise MetaDataError.new("Version is not in a valid format.") end log "Validating metadata..." log " Current version: #{@current_version}" log " Restored version: #{metadata[:version]}" if metadata[:version] > @current_version raise MigrationRequiredError.new( "You're trying to restore a more recent version of the schema. " \ "You should migrate first!", ) end metadata end protected # Tries to extract the backup version from an existing # metadata file (used in Discourse < v1.6) or from the filename. def extract_metadata metadata_path = File.join(@tmp_directory, METADATA_FILE) if @tmp_directory.present? if metadata_path.present? && File.exist?(metadata_path) metadata = load_metadata_file(metadata_path) elsif @filename =~ /-#{BackupRestore::VERSION_PREFIX}(\d{14})/ metadata = { version: Regexp.last_match[1].to_i } else raise MetaDataError.new("Migration version is missing from the filename.") end metadata end def load_metadata_file(path) metadata = JSON.parse(File.read(path), symbolize_names: true) raise MetaDataError.new("Failed to load metadata file.") if metadata.blank? metadata rescue JSON::ParserError raise MetaDataError.new("Failed to parse metadata file.") end end end