Skip to content

Commit

Permalink
Added Y2Packager::MediumType class
Browse files Browse the repository at this point in the history
  • Loading branch information
lslezak committed Sep 3, 2019
1 parent af1d6a6 commit 8910153
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 2 deletions.
102 changes: 102 additions & 0 deletions src/lib/y2packager/medium_type.rb
@@ -0,0 +1,102 @@
# ------------------------------------------------------------------------------
# Copyright (c) 2019 SUSE LLC, All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of version 2 of the GNU General Public License as published by the
# Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
# ------------------------------------------------------------------------------

require "yast"

require "y2packager/product_location"
require "y2packager/repomd_downloader"

Yast.import "InstURL"

module Y2Packager
# This class scans the installation medium type.
class MediumType
extend Yast::Logger

# Type of the installation medium
#
# @return [Symbol] Symbol describing the medium, one of `:offline`,
# `:online` or `:standard`
def self.type
@type ||= detect_medium_type
end

# Is the medium an online installation medium? (SLE Online)
# The online installation medium contains no repository
# or a repository without any base product.
def self.online?
type == :online
end

# Is the medium an offline installation medium? (SLE Offline)
# The offline installation medium contains several installation repositories.
# (At least one base product and one module/extension, usually there are
# several base products and many modules/extensions.)
def self.offline?
type == :offline
end

# Is the medium an standard installation medium? (openSUSE Leap)
# The standard installation medium contains a single repository
# with at least one base product. (Usually there is only one base product.)
def self.standard?
type == :standard
end

##############################################################################################

#
# Detect the medium type.
#
# @return [Symbol] Symbol describing the medium, one of `:offline`,
# `:online` or `:standard`
def self.detect_medium_type
url = Yast::InstURL.installInf2Url("")

raise "The installation URL is not set" if url.nil? || url.empty?

# scan the number of the products in the media.1/products file
downloader = Y2Packager::RepomdDownloader.new(url)
product_repos = downloader.product_repos

# the online medium should not contain any repository
# TODO: how to detect an invalid installation URL or a broken medium??
if product_repos.empty?
log.info("Detected medium type: online (no repository on the medium)")
return :online
end

# the offline medium contains several modules and extensions
if product_repos.size > 1
log.info("Detected medium type: offline (found #{product_repos.size} product repositories)")
return :offline
end

# preferred base product for scanning the products on the medium
base_product = nil
# run the scan even when there is only one repository on the medium
force_scan = true
base_products = Y2Packager::ProductLocation.scan(url, base_product, force_scan)
.select { |p| p.details&.base }

if base_products.empty?
log.info("Detected medium type: online (no base product found on the medium)")
:online
else
log.info("Detected medium type: standard (found #{base_products.size} base products)")
:standard
end
end

private_class_method :detect_medium_type
end
end
8 changes: 6 additions & 2 deletions src/lib/y2packager/product_location.rb
Expand Up @@ -42,16 +42,20 @@ class ProductLocation
# @param base_product [String,nil] The base product used for evaluating the
# product dependencies, if nil the solver can select any product to satisfy
# the dependencies.
# @param force_scan [Boolean] force evaluating the products (and their
# dependencies) even when there is only one repository on the medium.
# For the performance reasons the default is `false`, set `true` for
# special cases.
#
# @return [Array<Y2Packager::ProductLocation>] The found products
#
def self.scan(url, base_product = nil)
def self.scan(url, base_product = nil, force_scan = false)
log.info "Scanning #{Yast::URL.HidePassword(url)} for products..."

downloader = Y2Packager::RepomdDownloader.new(url)
# Skip the scan if there is none or just one repository, the repository selection
# is displayed only when there are at least 2 repositories.
return [] if downloader.product_repos.size < 2
return [] if downloader.product_repos.size < 2 && !force_scan

pool = Y2Packager::SolvablePool.new

Expand Down
80 changes: 80 additions & 0 deletions test/medium_type_test.rb
@@ -0,0 +1,80 @@
require_relative "test_helper"
require "y2packager/medium_type"

describe Y2Packager::MediumType do
Yast.import "Pkg"

let(:repo_url) { "http://example.com/repo" }

before do
allow(Yast::InstURL).to receive(:installInf2Url).and_return(repo_url)
end

after do
# the computed value is cached, we need to reset it manually for the next test
described_class.instance_variable_set(:@type, nil)
end

describe "#type" do
it "raises an exception when the installation URL is nil" do
expect(Yast::InstURL).to receive(:installInf2Url).and_return(nil)
expect { described_class.type }.to raise_exception(/The installation URL is not set/)
end

it "raises an exception when the installation URL is empty" do
expect(Yast::InstURL).to receive(:installInf2Url).and_return("")
expect { described_class.type }.to raise_exception(/The installation URL is not set/)
end

it "returns :online if no repository is found on the medium" do
expect_any_instance_of(Y2Packager::RepomdDownloader)
.to receive(:product_repos).and_return([])

expect(described_class.type).to eq(:online)
end

it "returns :offline if at least two repositories are found on the medium" do
expect_any_instance_of(Y2Packager::RepomdDownloader)
.to receive(:product_repos).and_return(
[
["Basesystem-Module 15.1-0", "/Module-Basesystem"],
["SLES15-SP1 15.1-0", "/Product-SLES"]
]
)

expect(described_class.type).to eq(:offline)
end

context "only one repository on the installation medium" do
before do
expect_any_instance_of(Y2Packager::RepomdDownloader)
.to receive(:product_repos).and_return(
[
["SLES15-SP1 15.1-0", "/"]
]
)
end

it "returns :online if the repository does not contain any base product" do
expect(Y2Packager::ProductLocation).to receive(:scan).and_return([])
expect(described_class.type).to eq(:online)
end

it "returns :standard if the repository contains any base product" do
details = Y2Packager::ProductLocationDetails.new(
product: "SLES",
summary: "SUSE Linux Enterprise Server 15 SP1",
description: "SUSE Linux Enterprise offers a comprehensive...",
order: 200,
base: true,
depends_on: [],
product_package: "sles-release"
)
prod = Y2Packager::ProductLocation.new("/", "/", product: details)

expect(Y2Packager::ProductLocation).to receive(:scan).and_return([prod])
expect(described_class.type).to eq(:standard)
end
end
end
end

0 comments on commit 8910153

Please sign in to comment.