Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions package/yast2-installation.spec
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ systemctl enable YaST2-Firstboot.service
%files
%defattr(-,root,root)

# data files
%{yast_ydatadir}

# systemd service files
%{_unitdir}/YaST2-Second-Stage.service
%{_unitdir}/YaST2-Firstboot.service
Expand Down
17 changes: 17 additions & 0 deletions src/data/old_packages/sle15_sp1.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
packages:
- name: yast2
version: 4.1.77-1.1
arch: x86_64
- name: yast2
version: 4.1.77-1.1
arch: aarch64

- name: yast2-pkg-bindings
version: 4.1.2-3.5.9
arch: x86_64
- name: yast2-pkg-bindings
version: 4.1.2-3.5.9
arch: aarch64

message: |
These packages are too old, newer packages should be preferred.
5 changes: 5 additions & 0 deletions src/lib/installation/clients/inst_doit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
# current contact information at www.novell.com.
# ------------------------------------------------------------------------------

require "installation/old_package_check"

module Yast
# Asks user to really do the installation/update.
class InstDoitClient < Client
Expand All @@ -41,6 +43,9 @@ def main
# bugzilla #256627
PackagesUI.ConfirmLicenses

# warn about installing old packages
::Installation::OldPackageCheck.run

# function in installation/misc.ycp
# bugzilla #219097
@confirmed = confirmInstallation
Expand Down
96 changes: 96 additions & 0 deletions src/lib/installation/old_package.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# ------------------------------------------------------------------------------
# Copyright (c) 2020 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 "yaml"
require "yast"

Yast.import "Pkg"
Yast.import "Report"

module Installation
# This class represents an old package which should not be installed by users.
class OldPackage
include Yast::Logger

attr_reader :name, :version, :arch, :message

# @param name [String] name of the package
# @param version [String] version of the package
# @param arch [String] architecture, e.g. "x86_64"
# @param message [String] the error message displayed to the user
# when an old package is selected
def initialize(name:, version:, arch:, message:)
@name = name
@version = version
@arch = arch
@message = message
end

# Finds the currently selected old package, if none or newer is selected then
# it returns `nil`.
# @return [Hash,nil] The selected old package or nil.
def selected_old
packages = Yast::Pkg.ResolvableProperties(name, :package, "")

# 1 = the selected is newer, the opposite is older or the same
Comment thread
lslezak marked this conversation as resolved.
Outdated
packages.find do |p|
p["status"] == :selected && p["arch"] == arch &&
Yast::Pkg.CompareVersions(version, p["version"]) == 1
end
end

# Reads the old package configuration files and creates the respective
# OldPackage objects.
Comment thread
lslezak marked this conversation as resolved.
Outdated
# @return [Array] Configured old packages, empty list if no configuration
# is specified
def self.read(paths = nil)
# unfortunately we cannot use Yast::Directory.find_data_file
# here because it needs an exact file name, it does not accept a glob,
# use Yast.y2paths to honor the Y2DIR setting
data_paths = paths || Yast.y2paths.map { |p| File.join(p, "data", "old_packages") }
data_paths.select { |p| File.directory?(p) }

log.debug "Found data directories: #{data_paths.inspect}"

data_files = data_paths.each_with_object([]) do |p, obj|
# find all *.yml and *.yaml files
obj.concat(Dir[File.join(p, "*.y{a,}ml")])
end

log.debug "Found data files: #{data_files.inspect}"

# remove the duplicates, this ensures the Y2DIR precedence
data_files.uniq! do |f|
File.basename(f)
end

log.debug "Unique data files: #{data_files.inspect}"

data_files.each_with_object([]) do |f, arr|
log.info "Loading file #{f.inspect}"

config = YAML.load_file(f)
message = config["message"] || ""
packages = config["packages"] || []

packages.each do |p|
arr << new(
name: p["name"],
version: p["version"],
arch: p["arch"],
message: message
)
end
end
end
end
end
30 changes: 30 additions & 0 deletions src/lib/installation/old_package_check.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# ------------------------------------------------------------------------------
# Copyright (c) 2020 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 "installation/old_package_report"
require "installation/old_package"

module Installation
# This class checks whether some old packages are selected
# and displays a warning to the user.
class OldPackageCheck
# Read the old package configurations and display warning for the old selected
# packages.
def self.run
old_packages = OldPackage.read
reporter = OldPackageReport.new(old_packages)
reporter.report
end
end
end
63 changes: 63 additions & 0 deletions src/lib/installation/old_package_report.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# ------------------------------------------------------------------------------
# Copyright (c) 2020 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"

Yast.import "Report"
Yast.import "HTML"

module Installation
# This class checks whether some old packages are selected
# and displays a warning to the user.
class OldPackageReport
Comment thread
lslezak marked this conversation as resolved.
Outdated
include Yast::Logger
include Yast::I18n

attr_reader :old_packages

# @param old_packages [Array<Installation::OldPackage>] old package configurations
def initialize(old_packages)
textdomain "installation"
@old_packages = old_packages
end

# report the selected old packages to the user
def report
report_packages = old_packages.select(&:selected_old)
if report_packages.empty?
log.info "No old package selected"
return
end

log.warn("Detected old packages in the package selection: #{report_packages.inspect}")

grouped_packages = report_packages.group_by(&:message)

pkg_summary = grouped_packages.each_with_object("") do |(msg, pkgs), str|
package_names = pkgs.map do |pkg|
old = pkg.selected_old
"#{old["name"]}-#{old["version"]}-#{old["arch"]}"
end

str << "<p>"
str << Yast::HTML.List(package_names)
str << msg
str << "</p><br>"
end

message = format(_("The installer detected old package versions selected " \
"for installation: \n\n%{list}"), list: pkg_summary)
Comment thread
lslezak marked this conversation as resolved.
Outdated

Yast::Report.LongWarning(message)
end
end
end
17 changes: 17 additions & 0 deletions test/data/old_packages/sle15_sp1_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
packages:
- name: yast2
version: 4.1.77-1.1
arch: x86_64
- name: yast2
version: 4.1.77-1.1
arch: aarch64

- name: yast2-pkg-bindings
version: 4.1.2-3.5.9
arch: x86_64
- name: yast2-pkg-bindings
version: 4.1.2-3.5.9
arch: aarch64

message: |
These packages are too old, newer packages should be preferred.
15 changes: 15 additions & 0 deletions test/old_package_check_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#! /usr/bin/env rspec

require_relative "test_helper"

require "installation/old_package_check"

describe Installation::OldPackageCheck do
describe ".run" do
it "reads old package configurations and reports the old packages" do
expect(Installation::OldPackage).to receive(:read)
expect_any_instance_of(Installation::OldPackageReport).to receive(:report)
Installation::OldPackageCheck.run
end
end
end
100 changes: 100 additions & 0 deletions test/old_package_report_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#! /usr/bin/env rspec

require_relative "test_helper"

require "installation/old_package"
require "installation/old_package_report"

describe Installation::OldPackageReport do
let(:message1) { "These packages are too old, install new ones." }
let(:message2) { "This package contains a bug." }
let(:old_package1) do
Installation::OldPackage.new(
name: "yast2",
version: "4.1.77-1.1",
arch: "x86_64",
message: message1
)
end
let(:old_package2) do
Installation::OldPackage.new(
name: "yast2-pkg-bindings",
version: "4.1.2-3.5.9",
arch: "x86_64",
message: message2
)
end

subject { Installation::OldPackageReport.new([old_package1, old_package2]) }

describe "#report" do
before do
expect(old_package1).to receive(:selected_old).at_least(:once)
.and_return(selected_package1)
expect(old_package2).to receive(:selected_old).at_least(:once)
.and_return(selected_package2)
end

context "No old package selected" do
let(:selected_package1) { nil }
let(:selected_package2) { nil }

it "does not report any error" do
expect(Yast::Report).to_not receive(:LongWarning)
subject.report
end
end

context "An old package is selected" do
let(:selected_package1) do
{
"name" => "yast2",
"version" => "4.1.77-1.1",
"arch" => "x86_64"
}
end
let(:selected_package2) { nil }

it "reports an error" do
expect(Yast::Report).to receive(:LongWarning).with(/#{message1}/)
subject.report
end
end

context "More old packages are selected" do
let(:selected_package1) do
{
"name" => "yast2",
"version" => "4.1.77-1.1",
"arch" => "x86_64"
}
end
let(:selected_package2) do
{
"name" => "yast2-pkg-bindings",
"version" => "4.1.2-3.5.9",
"arch" => "x86_64"
}
end

it "reports an error for all packages" do
expect(Yast::Report).to receive(:LongWarning) do |message|
expect(message).to include(message1)
expect(message).to include(message2)
end

subject.report
end

it "groups the packages with the same message" do
allow(old_package2).to receive(:message).and_return(message1)

expect(Yast::Report).to receive(:LongWarning) do |message|
expect(message.scan(message1).size).to eq(1)
end

subject.report
end
end
end
end
Loading