summaryrefslogtreecommitdiff
path: root/app/services/packages/debian/extract_metadata_service.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/services/packages/debian/extract_metadata_service.rb')
-rw-r--r--app/services/packages/debian/extract_metadata_service.rb85
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