Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/services/packages/rubygems/process_gem_service.rb')
-rw-r--r--app/services/packages/rubygems/process_gem_service.rb124
1 files changed, 124 insertions, 0 deletions
diff --git a/app/services/packages/rubygems/process_gem_service.rb b/app/services/packages/rubygems/process_gem_service.rb
new file mode 100644
index 00000000000..59bf2a1ec28
--- /dev/null
+++ b/app/services/packages/rubygems/process_gem_service.rb
@@ -0,0 +1,124 @@
+# frozen_string_literal: true
+
+require 'rubygems/package'
+
+module Packages
+ module Rubygems
+ class ProcessGemService
+ include Gitlab::Utils::StrongMemoize
+ include ExclusiveLeaseGuard
+
+ ExtractionError = Class.new(StandardError)
+ DEFAULT_LEASE_TIMEOUT = 1.hour.to_i.freeze
+
+ def initialize(package_file)
+ @package_file = package_file
+ end
+
+ def execute
+ return success if process_gem
+
+ error('Gem was not processed')
+ end
+
+ private
+
+ attr_reader :package_file
+
+ def process_gem
+ return false unless package_file
+
+ try_obtain_lease do
+ package.transaction do
+ rename_package_and_set_version
+ rename_package_file
+ ::Packages::Rubygems::MetadataExtractionService.new(package, gemspec).execute
+ ::Packages::Rubygems::CreateGemspecService.new(package, gemspec).execute
+ ::Packages::Rubygems::CreateDependenciesService.new(package, gemspec).execute
+ cleanup_temp_package
+ end
+ end
+
+ true
+ end
+
+ def rename_package_and_set_version
+ package.update!(
+ name: gemspec.name,
+ version: gemspec.version,
+ status: :default
+ )
+ end
+
+ def rename_package_file
+ # Updating file_name updates the path where the file is stored.
+ # We must pass the file again so that CarrierWave can handle the update
+ package_file.update!(
+ file_name: "#{gemspec.name}-#{gemspec.version}.gem",
+ file: package_file.file,
+ package_id: package.id
+ )
+ end
+
+ def cleanup_temp_package
+ temp_package.destroy if package.id != temp_package.id
+ end
+
+ def gemspec
+ strong_memoize(:gemspec) do
+ gem.spec
+ end
+ end
+
+ def success
+ ServiceResponse.success(payload: { package: package })
+ end
+
+ def error(message)
+ ServiceResponse.error(message: message)
+ end
+
+ def temp_package
+ strong_memoize(:temp_package) do
+ package_file.package
+ end
+ end
+
+ def package
+ strong_memoize(:package) do
+ # if package with name/version already exists, use that package
+ package = temp_package.project
+ .packages
+ .rubygems
+ .with_name(gemspec.name)
+ .with_version(gemspec.version.to_s)
+ .last
+ package || temp_package
+ end
+ end
+
+ def gem
+ # use_file will set an exclusive lease on the file for as long as
+ # the resulting gem object is being used. This means we are not
+ # able to rename the package_file while also using the gem object.
+ # We need to use a separate AR object to create the gem file to allow
+ # `package_file` to be free for update so we re-find the file here.
+ Packages::PackageFile.find(package_file.id).file.use_file do |file_path|
+ Gem::Package.new(File.open(file_path))
+ end
+ rescue
+ raise ExtractionError.new('Unable to read gem file')
+ end
+
+ # used by ExclusiveLeaseGuard
+ def lease_key
+ "packages:rubygems:process_gem_service:package:#{package.id}"
+ end
+
+ # used by ExclusiveLeaseGuard
+ def lease_timeout
+ DEFAULT_LEASE_TIMEOUT
+ end
+ end
+ end
+end