lib/rmt/cli/products.rb
require 'rmt/cli/repos'
class RMT::CLI::Products < RMT::CLI::Base
class ProductNotFoundException < StandardError
end
desc 'list', _('List products which are marked to be mirrored.')
option :all, aliases: '-a', type: :boolean, desc: _('List all products, including ones which are not marked to be mirrored')
option :release_stage, aliases: '-r', type: :string, desc: 'beta, released'
option :csv, type: :boolean, desc: _('Output data in CSV format')
option :name, type: :string, default: '', desc: _('Product name (e.g., Basesystem, SLES)')
option :version, type: :string, default: '', desc: _('Product version (e.g., 15, 15.1, \'12 SP4\')')
option :arch, type: :string, default: '', desc: _('Product architecture (e.g., x86_64, aarch64)')
def list
products = (options.all ? Product.all : Product.mirrored).order(:name, :version, :arch)
products = products.with_release_stage(options[:release_stage])
products = products.with_name_filter(options[:name])
products = products.with_version_filter(options[:version])
products = products.with_arch_filter(options[:arch])
decorator = ::RMT::CLI::Decorators::ProductDecorator.new(products)
if products.empty?
if options.all && options.name.blank? && options.version.blank? && options.arch.blank?
warn _("Run '%{command}' to synchronize with your SUSE Customer Center data first.") % { command: 'rmt-cli sync' }
else
warn _('No matching products found in the database.')
end
elsif options.csv
puts decorator.to_csv
else
puts decorator.to_table
end
unless options.all || options.csv
puts _("Only enabled products are shown by default. Use the '%{command}' option to see all products.") % {
command: '--all'
}
end
end
map 'ls' => :list
desc 'enable TARGETS', _('Enable mirroring of product repositories by a list of product IDs or product strings.')
option :all_modules, type: :boolean, desc: _('Enables all free modules for a product')
long_desc <<~REPOS
#{_('Enable mirroring of product repositories by a list of product IDs or product strings.')}
#{_('Examples')}:
$ rmt-cli products enable SLES/15
$ rmt-cli products enable 1575
$ rmt-cli products enable SLES/15/x86_64 1743
$ rmt-cli products enable --all-modules SLES/15
REPOS
def enable(*targets)
change_products(targets, true, options[:all_modules])
end
desc 'disable TARGETS', _('Disable mirroring of product repositories by a list of product IDs or product strings.')
long_desc <<~REPOS
#{_('Disable mirroring of product repositories by a list of product IDs or product strings.')}
#{_('Examples')}:
$ rmt-cli products disable SLES/15
$ rmt-cli products disable 1575
$ rmt-cli products disable SLES/15/x86_64 1743
REPOS
def disable(*targets)
change_products(targets, false, false)
puts "\n\e[1m" + _("To clean up downloaded files, run '%{command}'") % { command: 'rmt-cli repos clean' } + "\e[22m"
end
desc 'show TARGET', _('Displays product with all its repositories and their attributes.')
long_desc <<~SHOW
#{_('Displays product with all its repositories and their attributes.')}
#{_('Examples')}:
$ rmt-cli products show SLES/15/x86_64
SHOW
def show(target)
show_product(target)
end
protected
def show_product(target)
product = find_products(target).first
raise ProductNotFoundException.new(_('No product found for target %{target}.') % { target: target }) if product.blank?
puts _('Product: %{name} (ID: %{id})') % { name: product.friendly_name, id: product.id }
puts _('Description: %{description}') % { description: product.description }
show_product_repos(product)
rescue ProductNotFoundException => e
puts e.message
end
def show_product_repos(product)
repos = product.repositories
puts repos.present? ? _('Repositories:') : _('Repositories are not available for this product.')
decorator = ::RMT::CLI::Decorators::RepositoryDecorator.new(repos)
decorator.to_tty
end
def change_products(targets, set_enabled, all_modules)
targets = clean_target_input(targets)
raise RMT::CLI::Error.new(_('No product IDs supplied')) if targets.empty?
failed_targets = []
targets.each do |target|
change_product(target, set_enabled, all_modules)
rescue ProductNotFoundException => e
puts e.message
failed_targets << target
end
unless failed_targets.empty?
message = if set_enabled
n_('Product %{products} could not be found and was not enabled.',
'Products %{products} could not be found and were not enabled.',
failed_targets.count) % { products: failed_targets.join(', ') }
else
n_('Product %{products} could not be found and was not disabled.',
'Products %{products} could not be found and were not disabled.',
failed_targets.count) % { products: failed_targets.join(', ') }
end
raise RMT::CLI::Error.new(message)
end
end
def change_product(target, set_enabled, all_modules)
base_products = fetch_base_product target
base_products.each do |base_product|
products = [base_product]
if set_enabled
puts _('Enabling %{product}:') % { product: base_product.friendly_name }
extensions = all_modules ? Product.free_and_recommended_modules(base_product.id).to_a : Product.recommended_extensions(base_product.id).to_a
products.push(*extensions) unless extensions.empty?
else
puts _('Disabling %{product}:') % { product: base_product.friendly_name }
end
products.each do |product|
puts "#{product.friendly_name}:".indent(2)
repo_names = repository_service.change_mirroring_by_product!(set_enabled, product)
if repo_names.empty?
puts set_enabled ? _('All repositories have already been enabled.').indent(4) : _('All repositories have already been disabled.').indent(4)
next
end
repo_names.each do |repo_name|
if set_enabled
puts (_('Enabled repository %{repository}.') % { repository: repo_name }).indent(4)
else
puts (_('Disabled repository %{repository}.') % { repository: repo_name }).indent(4)
end
end
end
end
end
private
def fetch_base_product(target)
# This will return multiple products if 'SLES/15' was used
base_products = find_products(target)
raise ProductNotFoundException.new(_('No product found for target %{target}.') % { target: target }) if base_products.empty?
puts n_('Found product by target %{target}: %{products}.', 'Found products by target %{target}: %{products}.', base_products.count) % {
products: base_products.map(&:friendly_name).join(', '),
target: target
}
base_products
end
def find_products(target)
Product.get_by_target!(target)
rescue ActiveRecord::RecordNotFound
raise ProductNotFoundException.new(_('Product by ID %{id} not found.') % { id: target })
end
def repository_service
@repository_service ||= RepositoryService.new
end
# Allows to have any type of multi input that you want:
#
# 1575 (alone)
# SLES/15/x86_64,1743 (no space but with comma)
# SLES/15/x86_64, 1743 (space with comma)
# SLES/15/x86_64 1743 (space but no comma)
# "SLES/15/x86_64, 1743, SLED/15" (enclosed in spaces)
def clean_target_input(input)
input.inject([]) { |targets, object| targets + object.to_s.split(/,|\s/) }.reject(&:empty?)
end
end