diff options
Diffstat (limited to 'app/services/packages/debian/extract_metadata_service.rb')
-rw-r--r-- | app/services/packages/debian/extract_metadata_service.rb | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/app/services/packages/debian/extract_metadata_service.rb b/app/services/packages/debian/extract_metadata_service.rb new file mode 100644 index 00000000000..fd5832bc0ba --- /dev/null +++ b/app/services/packages/debian/extract_metadata_service.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +module Packages + module Debian + class ExtractMetadataService + include Gitlab::Utils::StrongMemoize + + ExtractionError = Class.new(StandardError) + + def initialize(package_file) + @package_file = package_file + end + + def execute + raise ExtractionError.new('invalid package file') unless valid_package_file? + + extract_metadata + end + + private + + attr_reader :package_file + + def valid_package_file? + package_file && + package_file.package&.debian? && + package_file.file.size > 0 # rubocop:disable Style/ZeroLengthPredicate + end + + def file_type_basic + %i[dsc deb udeb buildinfo changes].each do |format| + return format if package_file.file_name.end_with?(".#{format}") + end + + nil + end + + def file_type_source + # https://manpages.debian.org/buster/dpkg-dev/dpkg-source.1.en.html + %i[gzip bzip2 lzma xz].each do |format| + return :source if package_file.file_name.end_with?(".tar.#{format}") + end + + nil + end + + def file_type + strong_memoize(:file_type) do + file_type_basic || file_type_source || :unknown + end + end + + def file_type_debian? + file_type == :deb || file_type == :udeb + end + + def file_type_meta? + file_type == :dsc || file_type == :buildinfo || file_type == :changes + end + + def extracted_fields + if file_type_debian? + package_file.file.use_file do |file_path| + ::Packages::Debian::ExtractDebMetadataService.new(file_path).execute + end + elsif file_type_meta? + package_file.file.use_file do |file_path| + ::Packages::Debian::ParseDebian822Service.new(File.read(file_path)).execute.each_value.first + end + end + end + + def extract_metadata + fields = extracted_fields + architecture = fields.delete(:Architecture) if file_type_debian? + + { + file_type: file_type, + architecture: architecture, + fields: fields + } + end + end + end +end |