1
0
mirror of https://pagure.io/fedora-qa/os-autoinst-distri-fedora.git synced 2024-11-29 09:03:08 +00:00
os-autoinst-distri-fedora/lib/dnf.pm
2023-07-18 10:49:06 +02:00

212 lines
6.4 KiB
Perl

package dnf;
use strict;
use base 'Exporter';
use Exporter;
use lockapi;
use testapi;
use utils;
our @EXPORT = qw(install check remove reinstall parse_list_output parse_history_info latest_item parse_info parse_package_name confirm_in_lines confirm_in_output);
# This subroutine install a $package using DNF5.
# It dies if the command returns a non-zero exit
# code or if it times out.
sub install {
my $package = shift;
assert_script_run("dnf5 install -y $package", timeout => 120);
}
# This subroutine checks if the $package is installed
# using the rpm command. It returns True if it is
# installed.
sub check {
my $package = shift;
if (script_run("rpm -q $package", timeout => 60)) {
return 0;
}
else {
return 1;
}
}
# This subroutine removes the package using DNF5.
sub remove {
my $package = shift;
assert_script_run("dnf5 remove -y $package", timeout => 120);
}
# This subroutine reinstalls the package using DNF5.
sub reinstall {
my $package = shift;
assert_script_run("dnf5 reinstall -y $package", timeout => 120);
}
# This subroutine will parse the DNF5 cli output
# and return a hash with activities.
# Parsing the output is quite fragile, because
# the info is only divided by whitespaces and some
# columns are empty, so we retain column information
# in this case. Therefore, we will only consider
# the following structure, that will do for simple
# transactions:
# number : dnf5 : command : value : date
sub parse_list_output {
my $dnf = shift;
# Let us split the whole ouput into single lines
my @lines = split("\n", $dnf);
# The final hash with output information.
my $parsed_output = {};
# Let's iterate over the single lines and split
# them into single columns and store in the
# parsed output.
my $values = [];
for my $line (@lines) {
# Split columns on a white space.
my @columns = split(" ", $line);
# Take the columns
$values->[0] = $columns[1];
$values->[1] = $columns[2];
# When date comes on the third place, it means
# that the command did not have any arguments.
# We need to remember this and we will store
# an empty string instead.
if ($columns[3] =~ /\d\d\d\d-\d\d-\d\d/) {
$values->[2] = "";
$values->[3] = $columns[3];
}
# All DNF commands have the "-y" argument
# which we also need to think about.
elsif ($columns[3] eq "-y") {
$values->[2] = $columns[4];
$values->[3] = $columns[5];
}
else {
$values->[2] = $columns[3];
$values->[3] = $columns[4];
}
# The output also contains a description line that
# we do not want to store. That line leaves the "ID"
# string in the first place, so it is easy to find.
unless ($columns[0] eq "ID") {
$parsed_output->{$columns[0]} = $values;
}
}
return $parsed_output;
}
# This subroutine parses the DNF5 history info output. We will
# only consider several fields in order not to make things overly
# complicated, i.e. ID, user, status, releasever, and description.
sub parse_history_info {
my $dnf = shift;
# First, split into single lines.
my @lines = split("\n", $dnf);
# The final hash with output info
my $parsed_output = {};
# These are columns we are interested in.
my $selected = ["Transaction ID", "User", "Status", "Releasever", "Description"];
# Let us iterate over the lines and only choose info we want
for my $line (@lines) {
my @columns = split(" : ", $line);
# Trim the whitespaces from the column name
my $name = $columns[0];
$name =~ s/^\s+|\s+$//g;
# Only remember lines where $name matches
if ($name ~~ @$selected) {
$parsed_output->{$name} = $columns[1];
}
}
return $parsed_output;
}
# This subroutine returns the id number of the latest history item,
# based on the parsed history output, see parse_list_output.
sub latest_item {
# It takes the parsed data already.
my $dnfdata = shift;
# Take the keys list of ID numbers.
my @ids = keys %$dnfdata;
# Sort the keys as keys might not be sorted.
@ids = sort { $b <=> $a } @ids;
# The latest item, with highest number will now be at index 0.
return $ids[0];
}
# This subroutine parses info from the 'info' output
# and returns a hash where the output comprises
# of keys and values.
sub parse_info {
my $output = shift;
my $info = {};
my @output = split("\n", $output);
foreach (@output) {
my ($key, $value) = split(" : ", $_);
$key =~ s/^\s+|\s+$//g;
$value =~ s/^\s+|\s+$//g;
$info->{$key} = $value;
}
return $info;
}
# This routine takes the package name
# and splits it into various parts that are
# returned as a hash where the values are
# easily accessible.
sub parse_package_name {
my $rpm = shift;
my @rpm = split("-", $rpm);
my ($name, $version, $suffix) = split("-", $rpm);
my ($release, $os, $arch);
($release, $os, $arch, $suffix) = split(/\./, $suffix);
my $package = {};
$package->{name} = $name;
$package->{version} = $version;
$package->{release} = "$release.$os";
$package->{arch} = $arch;
return $package;
}
# This subroutine checks all the lines of $output
# for the $keyword and records all lines where
# the $keyword is not found and then it dies.
sub confirm_in_lines {
my ($output, $keyword) = @_;
my @unmatched;
my @lines = split("\n", $output);
# Iterate over the lines and record any line with a discrepancy
# into the unmatched array.
foreach (@lines) {
unless ($_ =~ /Updating and loading/ or $_ =~ /Repositories loaded/) {
unless ($_ =~ /$keyword/) {
push(@unmatched, $_);
}
}
}
# If there are errors in unmatched, log them and die.
if (scalar(@unmatched) > 0) {
diag("DNF5 Repoquerry errors:");
foreach (@unmatched) {
diag($_);
}
die("dnf5 repoquery returned lines that did not match the chosen pattern.");
}
}
# This subroutine checks that the $keyword
# exists in the $output and dies if it does not.
sub confirm_in_output {
my ($output, $keywords) = @_;
my @lines = split("\n", $output);
foreach (@$keywords) {
unless (grep(/$_/, @lines)) {
die("The $_ was not found in the output.");
}
}
}