# frozen_string_literal: true module Packages module Rpm class ParsePackageService include ::Gitlab::Utils::StrongMemoize BUILD_ATTRIBUTES_METHOD_NAMES = %i[changelogs requirements provides].freeze STATIC_ATTRIBUTES = %i[name version release summary description arch license sourcerpm group buildhost packager vendor].freeze CHANGELOGS_RPM_KEYS = %i[changelogtext changelogtime].freeze REQUIREMENTS_RPM_KEYS = %i[requirename requireversion requireflags].freeze PROVIDES_RPM_KEYS = %i[providename provideflags provideversion].freeze def initialize(package_file) @rpm = RPM::File.new(package_file) end def execute raise ArgumentError, 'Unable to parse package' unless valid_package? { files: rpm.files || [], epoch: package_tags[:epoch] || '0', changelogs: build_changelogs, requirements: build_requirements, provides: build_provides, directories: package_tags[:dirnames] }.merge(extract_static_attributes) end private attr_reader :rpm def valid_package? rpm.files && package_tags && true rescue RuntimeError # if arr-pm throws an error due to an incorrect file format, # we just want this validation to fail rather than throw an exception false end def package_tags strong_memoize(:package_tags) do rpm.tags end end def extract_static_attributes STATIC_ATTRIBUTES.index_with do |attribute| package_tags[attribute] end end # Define methods for building RPM attribute data from parsed package # Transform # changelogtime: [123, 234], # changelogname: ["First", "Second"] # changelogtext: ["Work1", "Work2"] # Into # changelog: [ # {changelogname: "First", changelogtext: "Work1", changelogtime: 123}, # {changelogname: "Second", changelogtext: "Work2", changelogtime: 234} # ] BUILD_ATTRIBUTES_METHOD_NAMES.each do |resource| define_method("build_#{resource}") do resource_keys = self.class.const_get("#{resource.upcase}_RPM_KEYS", false).dup return [] if resource_keys.any? { package_tags[_1].blank? } first_attributes = package_tags[resource_keys.first] zipped_data = first_attributes.zip(*resource_keys[1..].map { package_tags[_1] }) build_hashes(resource_keys, zipped_data) end end def build_hashes(resource_keys, zipped_data) zipped_data.map do |data| resource_keys.zip(data).to_h end end end end end