debian-mirror-gitlab/app/services/packages/debian/process_package_file_service.rb
2023-06-20 00:43:36 +05:30

162 lines
4.8 KiB
Ruby

# frozen_string_literal: true
module Packages
module Debian
class ProcessPackageFileService
include ExclusiveLeaseGuard
include Gitlab::Utils::StrongMemoize
SOURCE_FIELD_SPLIT_REGEX = /[ ()]/
# used by ExclusiveLeaseGuard
DEFAULT_LEASE_TIMEOUT = 1.hour.to_i.freeze
def initialize(package_file, distribution_name, component_name)
@package_file = package_file
@distribution_name = distribution_name
@component_name = component_name
end
def execute
return if @package_file.package.pending_destruction?
validate!
try_obtain_lease do
package.transaction do
rename_package_and_set_version
update_package
update_file_metadata
cleanup_temp_package
end
::Packages::Debian::GenerateDistributionWorker.perform_async(:project, package.debian_distribution.id)
end
end
private
def validate!
raise ArgumentError, 'missing distribution name' unless @distribution_name.present?
raise ArgumentError, 'missing component name' unless @component_name.present?
raise ArgumentError, 'package file without Debian metadata' unless @package_file.debian_file_metadatum
raise ArgumentError, 'already processed package file' unless @package_file.debian_file_metadatum.unknown?
if file_metadata[:file_type] == :deb || file_metadata[:file_type] == :udeb || file_metadata[:file_type] == :ddeb
return
end
raise ArgumentError, "invalid package file type: #{file_metadata[:file_type]}"
end
def file_metadata
::Packages::Debian::ExtractMetadataService.new(@package_file).execute
end
strong_memoize_attr :file_metadata
def package
packages = temp_package.project
.packages
.existing_debian_packages_with(name: package_name, version: package_version)
package = packages.with_debian_codename_or_suite(@distribution_name)
.first
unless package
package_in_other_distribution = packages.first
if package_in_other_distribution
raise ArgumentError, "Debian package #{package_name} #{package_version} exists " \
"in distribution #{package_in_other_distribution.debian_distribution.codename}"
end
end
package || temp_package
end
strong_memoize_attr :package
def temp_package
@package_file.package
end
strong_memoize_attr :temp_package
def package_name
package_name_and_version[0]
end
def package_version
package_name_and_version[1]
end
def package_name_and_version
package_name = file_metadata[:fields]['Package']
package_version = file_metadata[:fields]['Version']
if file_metadata[:fields]['Source']
# "sample" or "sample (1.2.3~alpha2)"
source_field_parts = file_metadata[:fields]['Source'].split(SOURCE_FIELD_SPLIT_REGEX)
package_name = source_field_parts[0]
package_version = source_field_parts[2] || package_version
end
[package_name, package_version]
end
strong_memoize_attr :package_name_and_version
def rename_package_and_set_version
package.update!(
name: package_name,
version: package_version,
status: :default
)
end
def update_package
return unless using_temporary_package?
package.update!(
debian_publication_attributes: { distribution_id: distribution.id }
)
end
def using_temporary_package?
package.id == temp_package.id
end
def distribution
Packages::Debian::DistributionsFinder.new(
@package_file.package.project,
codename_or_suite: @distribution_name
).execute.last!
end
strong_memoize_attr :distribution
def update_file_metadata
::Packages::UpdatePackageFileService.new(@package_file, package_id: package.id)
.execute
# Force reload from database, as package has changed
@package_file.reload_package
@package_file.debian_file_metadatum.update!(
file_type: file_metadata[:file_type],
component: @component_name,
architecture: file_metadata[:architecture],
fields: file_metadata[:fields]
)
end
def cleanup_temp_package
temp_package.destroy unless using_temporary_package?
end
# used by ExclusiveLeaseGuard
def lease_key
"packages:debian:process_package_file_service:package_file:#{@package_file.id}"
end
# used by ExclusiveLeaseGuard
def lease_timeout
DEFAULT_LEASE_TIMEOUT
end
end
end
end