summaryrefslogtreecommitdiff
path: root/lib/gitlab/composer/cache.rb
blob: 1f404d630475e357c8ea8d2aae0b1ecbd33d9109 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# frozen_string_literal: true

require 'tempfile'

module Gitlab
  module Composer
    class Cache
      def initialize(project:, name:, last_page_sha: nil)
        @project = project
        @name = name
        @last_page_sha = last_page_sha
      end

      def execute
        Packages::Composer::Metadatum.transaction do # rubocop: disable CodeReuse/ActiveRecord
          # make sure we lock these records at the start
          locked_package_metadata

          if locked_package_metadata.any?
            mark_pages_for_delete(shas_to_delete)

            create_cache_page!

            # assign the newest page SHA to the packages
            locked_package_metadata.update_all(version_cache_sha: version_index.sha)
          elsif @last_page_sha
            mark_pages_for_delete([@last_page_sha])
          end
        end
      end

      private

      def mark_pages_for_delete(shas)
        Packages::Composer::CacheFile
          .with_namespace(@project.namespace)
          .with_sha(shas)
          .update_all(delete_at: 1.day.from_now)
      end

      def create_cache_page!
        Packages::Composer::CacheFile
          .safe_find_or_create_by!(namespace_id: @project.namespace_id, file_sha256: version_index.sha) do |cache_file|
            cache_file.file = CarrierWaveStringFile.new(version_index.to_json)
          end
      end

      def version_index
        @version_index ||= ::Gitlab::Composer::VersionIndex.new(siblings)
      end

      def siblings
        @siblings ||= locked_package_metadata.map(&:package)
      end

      # find all metadata of the package versions and lock it for update
      def locked_package_metadata
        @locked_package_metadata ||= Packages::Composer::Metadatum
          .for_package(@name, @project.id)
          .locked_for_update
      end

      def shas_to_delete
        locked_package_metadata
          .map(&:version_cache_sha)
          .reject { |sha| sha == version_index.sha }
          .compact
      end
    end
  end
end