Skip to content

Commit

Permalink
Merge pull request #4080 from hennevogel/bugfix/kiwi_image_classes
Browse files Browse the repository at this point in the history
[frontend] Use nested module syntax for Kiwi classes
  • Loading branch information
hennevogel committed Oct 27, 2017
2 parents 79ebf1f + 356e482 commit 10d63da
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 220 deletions.
208 changes: 105 additions & 103 deletions src/api/app/models/kiwi/image.rb
@@ -1,126 +1,128 @@
class Kiwi::Image < ApplicationRecord
#### Includes and extends

#### Constants
DEFAULT_KIWI_BODY = '<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="6.2" name="suse-13.2-live">
<description type="system">
</description>
<preferences>
<type image="oem" primary="true" boot="oemboot/suse-13.2"/>
</preferences>
</image>
'.freeze

#### Self config
#### Attributes

#### Associations macros (Belongs to, Has one, Has many)
has_one :package, foreign_key: 'kiwi_image_id', class_name: '::Package', dependent: :nullify, inverse_of: :kiwi_image
has_many :repositories, -> { order(order: :asc) }, dependent: :destroy, index_errors: true
has_many :package_groups, -> { order(:id) }, dependent: :destroy, index_errors: true
has_many :kiwi_packages, -> { where(kiwi_package_groups: { kiwi_type: Kiwi::PackageGroup.kiwi_types[:image] }) },
through: :package_groups, source: :packages, inverse_of: :kiwi_image

#### Callbacks macros: before_save, after_save, etc.

#### Scopes (first the default_scope macro if is used)

#### Validations macros
validates :name, presence: true
validate :check_use_project_repositories
validate :check_package_groups
accepts_nested_attributes_for :repositories, allow_destroy: true
accepts_nested_attributes_for :package_groups, allow_destroy: true
accepts_nested_attributes_for :kiwi_packages, allow_destroy: true

#### Class methods using self. (public and then private)

#### To define class methods as private use private_class_method
#### private

#### Instance methods (public and then protected/private)

#### Alias of methods
def self.build_from_xml(xml_string, md5)
Kiwi::Image::XmlParser.new(xml_string, md5).parse
end
module Kiwi
class Image < ApplicationRecord
#### Includes and extends

#### Constants
DEFAULT_KIWI_BODY = '<?xml version="1.0" encoding="utf-8"?>
<image schemaversion="6.2" name="suse-13.2-live">
<description type="system">
</description>
<preferences>
<type image="oem" primary="true" boot="oemboot/suse-13.2"/>
</preferences>
</image>
'.freeze

#### Self config
#### Attributes

#### Associations macros (Belongs to, Has one, Has many)
has_one :package, foreign_key: 'kiwi_image_id', class_name: '::Package', dependent: :nullify, inverse_of: :kiwi_image
has_many :repositories, -> { order(order: :asc) }, dependent: :destroy, index_errors: true
has_many :package_groups, -> { order(:id) }, dependent: :destroy, index_errors: true
has_many :kiwi_packages, -> { where(kiwi_package_groups: { kiwi_type: Kiwi::PackageGroup.kiwi_types[:image] }) },
through: :package_groups, source: :packages, inverse_of: :kiwi_image

#### Callbacks macros: before_save, after_save, etc.

#### Scopes (first the default_scope macro if is used)

#### Validations macros
validates :name, presence: true
validate :check_use_project_repositories
validate :check_package_groups
accepts_nested_attributes_for :repositories, allow_destroy: true
accepts_nested_attributes_for :package_groups, allow_destroy: true
accepts_nested_attributes_for :kiwi_packages, allow_destroy: true

#### Class methods using self. (public and then private)

#### To define class methods as private use private_class_method
#### private

#### Instance methods (public and then protected/private)

#### Alias of methods
def self.build_from_xml(xml_string, md5)
Kiwi::Image::XmlParser.new(xml_string, md5).parse
end

def to_xml
Kiwi::Image::XmlBuilder.new(self).build
end
def to_xml
Kiwi::Image::XmlBuilder.new(self).build
end

def write_to_backend
return false unless package
def write_to_backend
return false unless package

Package.transaction do
file_name = package.kiwi_image_file || "#{package.name}.kiwi"
package.save_file({ filename: file_name, file: to_xml })
self.md5_last_revision = package.kiwi_file_md5
save!
Package.transaction do
file_name = package.kiwi_image_file || "#{package.name}.kiwi"
package.save_file({ filename: file_name, file: to_xml })
self.md5_last_revision = package.kiwi_file_md5
save!
end
end
end

def outdated?
return false unless package
def outdated?
return false unless package

package.kiwi_image_outdated?
end
package.kiwi_image_outdated?
end

def default_package_group
package_groups.type_image.first || package_groups.create(kiwi_type: :image, pattern_type: 'onlyRequired')
end
def default_package_group
package_groups.type_image.first || package_groups.create(kiwi_type: :image, pattern_type: 'onlyRequired')
end

def self.find_binaries_by_name(query, project, repositories, options = {})
finder = /\A#{Regexp.quote(query)}/
binaries_available(project, options[:use_project_repositories], repositories).select { |package, _| finder.match(package.to_s) }
end
def self.find_binaries_by_name(query, project, repositories, options = {})
finder = /\A#{Regexp.quote(query)}/
binaries_available(project, options[:use_project_repositories], repositories).select { |package, _| finder.match(package.to_s) }
end

def self.binaries_available(project, use_project_repositories, repositories)
Rails.cache.fetch("kiwi_image_binaries_available_#{project}_#{use_project_repositories}_#{repositories}", expires_in: 5.minutes) do
if use_project_repositories
Backend::Api::BuildResults::Binaries.available_in_project(project)
else
return [] if repositories.blank?
obs_repository_paths = repositories.select { |url| url.starts_with?("obs://")}.map {|url| url[6..-1] }
non_obs_repository_urls = repositories.reject { |url| url.starts_with?("obs://")}
Backend::Api::BuildResults::Binaries.available_in_repositories(project, non_obs_repository_urls, obs_repository_paths)
def self.binaries_available(project, use_project_repositories, repositories)
Rails.cache.fetch("kiwi_image_binaries_available_#{project}_#{use_project_repositories}_#{repositories}", expires_in: 5.minutes) do
if use_project_repositories
Backend::Api::BuildResults::Binaries.available_in_project(project)
else
return [] if repositories.blank?
obs_repository_paths = repositories.select { |url| url.starts_with?("obs://")}.map {|url| url[6..-1] }
non_obs_repository_urls = repositories.reject { |url| url.starts_with?("obs://")}
Backend::Api::BuildResults::Binaries.available_in_repositories(project, non_obs_repository_urls, obs_repository_paths)
end
end
end
end

# This method is for parse the error messages and group them to make them more understandable.
# The nested errors messages are like `Model[0] attributes` and this is not easy to understand.
def parsed_errors(title, packages)
message = { title: title }
message["Image Errors:"] = errors.messages[:base] if errors.messages[:base].present?

{ repository: repositories, package: packages }.each do |key, records|
records.each do |record|
if record.errors.present?
message["#{key.capitalize}: #{record.name}"] ||= []
message["#{key.capitalize}: #{record.name}"] << record.errors.messages.values
message["#{key.capitalize}: #{record.name}"].flatten!
# This method is for parse the error messages and group them to make them more understandable.
# The nested errors messages are like `Model[0] attributes` and this is not easy to understand.
def parsed_errors(title, packages)
message = { title: title }
message["Image Errors:"] = errors.messages[:base] if errors.messages[:base].present?

{ repository: repositories, package: packages }.each do |key, records|
records.each do |record|
if record.errors.present?
message["#{key.capitalize}: #{record.name}"] ||= []
message["#{key.capitalize}: #{record.name}"] << record.errors.messages.values
message["#{key.capitalize}: #{record.name}"].flatten!
end
end
end
end

message
end
message
end

private
private

def check_use_project_repositories
return unless use_project_repositories? && repositories.present?
def check_use_project_repositories
return unless use_project_repositories? && repositories.present?

errors.add(:base,
"A repository with source_path \"obsrepositories:/\" has been set. If you want to use it, please remove the other repositories.")
end
errors.add(:base,
"A repository with source_path \"obsrepositories:/\" has been set. If you want to use it, please remove the other repositories.")
end

def check_package_groups
return if package_groups.group_by(&:kiwi_type).select { |_key, value| value.count > 1 }.keys.empty?
def check_package_groups
return if package_groups.group_by(&:kiwi_type).select { |_key, value| value.count > 1 }.keys.empty?

errors.add(:base, "Multiple package groups with same type are not allowed.")
errors.add(:base, "Multiple package groups with same type are not allowed.")
end
end
end

Expand Down
24 changes: 13 additions & 11 deletions src/api/app/models/kiwi/package.rb
@@ -1,16 +1,18 @@
class Kiwi::Package < ApplicationRecord
belongs_to :package_group
has_one :kiwi_image, through: :package_groups
module Kiwi
class Package < ApplicationRecord
belongs_to :package_group
has_one :kiwi_image, through: :package_groups

validates :name, presence: { message: 'Package name can\'t be blank'}
validates :name, presence: { message: 'Package name can\'t be blank'}

def to_h
hash = { name: name }
hash[:arch] = arch if arch.present?
hash[:replaces] = replaces if replaces.present?
hash[:bootinclude] = bootinclude if bootinclude.present?
hash[:bootdelete] = bootdelete if bootdelete.present?
hash
def to_h
hash = { name: name }
hash[:arch] = arch if arch.present?
hash[:replaces] = replaces if replaces.present?
hash[:bootinclude] = bootinclude if bootinclude.present?
hash[:bootdelete] = bootdelete if bootdelete.present?
hash
end
end
end

Expand Down
48 changes: 25 additions & 23 deletions src/api/app/models/kiwi/package_group.rb
@@ -1,35 +1,37 @@
class Kiwi::PackageGroup < ApplicationRecord
has_many :packages, dependent: :destroy
belongs_to :image
module Kiwi
class PackageGroup < ApplicationRecord
has_many :packages, dependent: :destroy
belongs_to :image

# we need to add a prefix, to avoid generating class methods that already
# exist in Active Record, such as "delete"
enum kiwi_type: %i[bootstrap delete docker image iso lxc oem pxe split testsuite vmx], _prefix: :type
# we need to add a prefix, to avoid generating class methods that already
# exist in Active Record, such as "delete"
enum kiwi_type: %i[bootstrap delete docker image iso lxc oem pxe split testsuite vmx], _prefix: :type

scope :type_image, -> { where(kiwi_type: :image) }
scope :type_image, -> { where(kiwi_type: :image) }

validates :kiwi_type, presence: true
validates :kiwi_type, presence: true

accepts_nested_attributes_for :packages, reject_if: :all_blank, allow_destroy: true
accepts_nested_attributes_for :packages, reject_if: :all_blank, allow_destroy: true

def to_xml
return '' if packages.empty?
group_attributes = { type: kiwi_type }
group_attributes[:profiles] = profiles if profiles.present?
group_attributes[:patternType] = pattern_type if pattern_type.present?
def to_xml
return '' if packages.empty?
group_attributes = { type: kiwi_type }
group_attributes[:profiles] = profiles if profiles.present?
group_attributes[:patternType] = pattern_type if pattern_type.present?

builder = Nokogiri::XML::Builder.new
builder.packages(group_attributes) do |group|
packages.each do |package|
group.package(package.to_h)
builder = Nokogiri::XML::Builder.new
builder.packages(group_attributes) do |group|
packages.each do |package|
group.package(package.to_h)
end
end
end

builder.to_xml save_with: Nokogiri::XML::Node::SaveOptions::NO_DECLARATION | Nokogiri::XML::Node::SaveOptions::FORMAT
end
builder.to_xml save_with: Nokogiri::XML::Node::SaveOptions::NO_DECLARATION | Nokogiri::XML::Node::SaveOptions::FORMAT
end

def kiwi_type_image?
kiwi_type == 'image'
def kiwi_type_image?
kiwi_type == 'image'
end
end
end

Expand Down

0 comments on commit 10d63da

Please sign in to comment.