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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
# frozen_string_literal: true
class Packages::PackageFile < ApplicationRecord
include UpdateProjectStatistics
include FileStoreMounter
include Packages::Installable
include Packages::Destructible
INSTALLABLE_STATUSES = [:default].freeze
delegate :project, :project_id, to: :package
delegate :conan_file_type, to: :conan_file_metadatum
delegate :file_type, :dsc?, :component, :architecture, :fields, to: :debian_file_metadatum, prefix: :debian
delegate :channel, :metadata, to: :helm_file_metadatum, prefix: :helm
enum status: { default: 0, pending_destruction: 1, processing: 2, error: 3 }
belongs_to :package
# used to move the linked file within object storage
attribute :new_file_path, default: nil
has_one :conan_file_metadatum, inverse_of: :package_file, class_name: 'Packages::Conan::FileMetadatum'
has_many :package_file_build_infos, inverse_of: :package_file, class_name: 'Packages::PackageFileBuildInfo'
has_many :pipelines, through: :package_file_build_infos, disable_joins: true
has_one :debian_file_metadatum, inverse_of: :package_file, class_name: 'Packages::Debian::FileMetadatum'
has_one :helm_file_metadatum, inverse_of: :package_file, class_name: 'Packages::Helm::FileMetadatum'
accepts_nested_attributes_for :conan_file_metadatum
accepts_nested_attributes_for :debian_file_metadatum
accepts_nested_attributes_for :helm_file_metadatum
validates :package, presence: true
validates :file, presence: true
validates :file_name, presence: true
validates :file_name, uniqueness: { scope: :package }, if: -> { package&.pypi? }
scope :recent, -> { order(id: :desc) }
scope :limit_recent, ->(limit) { recent.limit(limit) }
scope :for_package_ids, ->(ids) { where(package_id: ids) }
scope :with_file_name, ->(file_name) { where(file_name: file_name) }
scope :with_file_name_like, ->(file_name) { where(arel_table[:file_name].matches(file_name)) }
scope :with_files_stored_locally, -> { where(file_store: ::Packages::PackageFileUploader::Store::LOCAL) }
scope :with_format, ->(format) { where(::Packages::PackageFile.arel_table[:file_name].matches("%.#{format}")) }
scope :preload_package, -> { preload(:package) }
scope :preload_pipelines, -> { preload(pipelines: :user) }
scope :preload_conan_file_metadata, -> { preload(:conan_file_metadatum) }
scope :preload_debian_file_metadata, -> { preload(:debian_file_metadatum) }
scope :preload_helm_file_metadata, -> { preload(:helm_file_metadatum) }
scope :for_rubygem_with_file_name, ->(project, file_name) do
joins(:package).merge(project.packages.rubygems).with_file_name(file_name)
end
scope :for_helm_with_channel, ->(project, channel) do
result = joins(:package)
.merge(project.packages.helm.installable)
.joins(:helm_file_metadatum)
.where(packages_helm_file_metadata: { channel: channel })
result = result.installable if Feature.enabled?(:packages_installable_package_files, default_enabled: :yaml)
result
end
scope :with_conan_file_type, ->(file_type) do
joins(:conan_file_metadatum)
.where(packages_conan_file_metadata: { conan_file_type: ::Packages::Conan::FileMetadatum.conan_file_types[file_type] })
end
scope :with_debian_file_type, ->(file_type) do
joins(:debian_file_metadatum)
.where(packages_debian_file_metadata: { file_type: ::Packages::Debian::FileMetadatum.file_types[file_type] })
end
scope :with_debian_component_name, ->(component_name) do
joins(:debian_file_metadatum)
.where(packages_debian_file_metadata: { component: component_name })
end
scope :with_debian_architecture_name, ->(architecture_name) do
joins(:debian_file_metadatum)
.where(packages_debian_file_metadata: { architecture: architecture_name })
end
scope :with_conan_package_reference, ->(conan_package_reference) do
joins(:conan_file_metadatum)
.where(packages_conan_file_metadata: { conan_package_reference: conan_package_reference })
end
def self.most_recent!
recent.first!
end
mount_file_store_uploader Packages::PackageFileUploader
update_project_statistics project_statistics_name: :packages_size
before_save :update_size_from_file
# if a new_file_path is provided, we need
# * disable the remove_previously_stored_file callback so that carrierwave doesn't take care of the file
# * enable a new after_commit callback that will move the file in object storage
skip_callback :commit, :after, :remove_previously_stored_file, if: :execute_move_in_object_storage?
after_commit :move_in_object_storage, if: :execute_move_in_object_storage?
# Returns the most recent installable package file for *each* of the given packages.
# The order is not guaranteed.
def self.most_recent_for(packages, extra_join: nil, extra_where: nil)
cte_name = :packages_cte
cte = Gitlab::SQL::CTE.new(cte_name, packages.select(:id))
package_files = if Feature.enabled?(:packages_installable_package_files, default_enabled: :yaml)
::Packages::PackageFile.installable.limit_recent(1)
.where(arel_table[:package_id].eq(Arel.sql("#{cte_name}.id")))
else
::Packages::PackageFile.limit_recent(1)
.where(arel_table[:package_id].eq(Arel.sql("#{cte_name}.id")))
end
package_files = package_files.joins(extra_join) if extra_join
package_files = package_files.where(extra_where) if extra_where
query = select('finder.*')
.from([Arel.sql(cte_name.to_s), package_files.arel.lateral.as('finder')])
query.with(cte.to_arel)
end
def download_path
Gitlab::Routing.url_helpers.download_project_package_file_path(project, self)
end
private
def update_size_from_file
self.size ||= file.size
end
def execute_move_in_object_storage?
!file.file_storage? && new_file_path?
end
def move_in_object_storage
carrierwave_file = file.file
carrierwave_file.copy_to(new_file_path)
carrierwave_file.delete
end
end
Packages::PackageFile.prepend_mod_with('Packages::PackageFile')
|