File Coverage

blib/lib/RPM/Query.pm
Criterion Covered Total %
statement 21 88 23.8
branch 0 24 0.0
condition 0 6 0.0
subroutine 7 19 36.8
pod 9 9 100.0
total 37 146 25.3


line stmt bran cond sub pod time code
1             package RPM::Query;
2 5     5   294529 use strict;
  5         42  
  5         205  
3 5     5   24 use warnings;
  5         8  
  5         120  
4 5     5   22 use base qw{Package::New};
  5         18  
  5         1938  
5 5     5   1059 use List::Util qw{uniq};
  5         9  
  5         423  
6 5     5   2221 use IPC::Run3 qw{};
  5         142853  
  5         129  
7 5     5   1861 use RPM::Query::Package;
  5         12  
  5         114  
8 5     5   1666 use RPM::Query::Capability;
  5         10  
  5         4322  
9              
10             our $VERSION = '0.02';
11              
12             =head1 NAME
13              
14             RPM::Query - Perl object overlay of the RPM query command
15              
16             =head1 SYNOPSIS
17              
18              
19             use RPM::Query;
20             my $rpm = RPM::Query->new;
21             my $pkg = $rpm->query('perl');
22             my $requires = $pkg->requires;
23             foreach my $capability (@$requires) {
24             printf "Capability: %s\n", $capability->name;
25             my $whatprovides = $capability->whatprovides;
26             foreach my $package (@$whatprovides) { #could be zero or more but normally one
27             printf " Package: %s\n", $package->package_name;
28             }
29             }
30              
31             =head1 DESCRIPTION
32              
33             =head1 METHODS
34              
35             =head2 query
36              
37             Returns an the last object of the passed in package name or undef if not installed.
38              
39             my $package_obj = $rpm->query("my_package") or die("my_package is not installed");
40             my $long_name = $package_obj->package_name;
41              
42             Wrapper around
43              
44             $ rpm --query | tail -n 1
45             perl-5.16.3-299.el7_9.x86_64
46              
47             =cut
48              
49             sub query {
50 0     0 1   my $self = shift;
51 0 0         my $name = shift or die;
52 0           my $array = $self->query_list($name);
53 0           return $array->[-1];
54             }
55              
56             =head2 query_list
57              
58             my $packages_aref = $rpm->query("kernel");
59              
60             Wrapper around
61              
62             $ rpm -q kernel
63             kernel-3.10.0-1160.76.1.el7.x86_64
64             kernel-3.10.0-1160.80.1.el7.x86_64
65             kernel-3.10.0-1160.81.1.el7.x86_64
66             kernel-3.10.0-1160.83.1.el7.x86_64
67             kernel-3.10.0-1160.88.1.el7.x86_64
68              
69             =cut
70              
71             sub query_list {
72 0     0 1   my $self = shift;
73 0 0         my $name = shift or die;
74 0           my $array = $self->_run3_array('--query' => $name);
75 0           return [map {RPM::Query::Package->new(package_name=>$_, parent=>$self)} @$array];
  0            
76             }
77              
78             =head2 details
79              
80             Returns a HASH data structure of the details of the passed in package name.
81              
82             my $hash = $rpm->details("my_package");
83             my $version = $hash->{'version'};
84              
85             Wrapper around
86              
87             $ rpm --query perl --queryformat '%{name} %{version} ...'
88             perl 5.16.3 ...
89              
90             =cut
91              
92             our @QUERY_FORMAT_FIELDS = qw{name version release epoch arch group size license packager url summary description sourcerpm sigmd5 buildtime buildhost installtime distribution vendor}; #rpm info plus
93              
94             sub details {
95 0     0 1   my $self = shift;
96 0 0         my $arg = shift or die;
97 0           my $format = join('|x1|', map {"%{$_}"} @QUERY_FORMAT_FIELDS); #delimiter is '|x1|'
  0            
98 0           my $scalar = $self->_run3_scalar('--query' => $arg, '--queryformat' => $format); #isa ARRAY
99 0           my %hash = ();
100 0           @hash{@QUERY_FORMAT_FIELDS} = split /\|x1\|/, $scalar; #hash slice assignment
101 0           return \%hash;
102             }
103              
104             =head2 verify
105              
106             Returns true if verify is clean
107              
108             Wrapper around
109              
110             $ rpm --verify perl && echo 1 || echo 0
111             1
112              
113             =cut
114              
115             sub verify {
116 0     0 1   my $self = shift;
117 0           my $name = shift;
118 0           my $error = $self->_run3_error('--verify' => $name);
119 0           return !$error;
120             }
121              
122             =head2 whatprovides
123              
124             Returns a list of packages that provides the capability
125              
126             my $package = $rpm->whatprovides('perl(strict)'); #isa ARRAY of RPM::Query::Package
127              
128             Wrapper around
129              
130             $ rpm --query --whatprovides 'perl(strict)'
131             perl-5.16.3-299.el7_9.x86_64
132              
133             =cut
134              
135             sub whatprovides {
136 0     0 1   my $self = shift;
137 0 0         my $capability = shift or die;
138 0           my $array = $self->_run3_array('--query' => '--whatprovides' => $capability);
139 0           return [map {RPM::Query::Package->new(package_name=>$_, parent=>$self)} uniq sort @$array];
  0            
140             }
141              
142             =head2 provides
143              
144             Returns a list of capabilities that the installed package provides
145              
146             my $capabilities = $rpm->provides('perl'); #isa ARRAY of RPM::Query::Capability objects
147              
148             Wrapper around
149              
150             $ rpm --query --provides 'perl'
151             perl = 4:5.16.3-299.el7_9
152             perl(AutoLoader) = 5.72
153             perl(B) = 1.35
154             perl(B::Section)
155             ...
156              
157             =cut
158              
159             sub provides {
160 0     0 1   my $self = shift;
161 0 0         my $capability = shift or die;
162 0           my $array = $self->_run3_array('--query' => '--provides' => $capability);
163 0           return [map {RPM::Query::Capability->new(capability_name=>$_, parent=>$self)} uniq sort @$array];
  0            
164             }
165              
166             =head2 requires
167              
168             Returns a list of capabilities that the package requires
169              
170             my $capabilities = $rpm->requires('perl'); #isa ARRAY of RPM::Query::Capability objects
171              
172             Wrapper around
173              
174             $ rpm --query --requires perl
175             /usr/bin/perl
176             libpthread.so.0()(64bit)
177             perl >= 0:5.000
178             ...
179              
180             =cut
181              
182             sub requires {
183 0     0 1   my $self = shift;
184 0 0         my $capability = shift or die;
185 0           my $array = $self->_run3_array('--query' => '--requires' => $capability);
186 0           return [map {RPM::Query::Capability->new(capability_name=>$_, parent=>$self)} uniq sort @$array];
  0            
187             }
188              
189             =head2 whatrequires
190              
191             Returns a list of packages that this capability requires
192              
193             my $capabilities = $rpm->whatrequires('perl'); #isa ARRAY of RPM::Query::Package objects
194              
195             Wrapper around
196              
197             $ rpm --query --whatrequires perl
198             perl-podlators-2.5.1-3.el7.noarch
199             perl-Pod-Perldoc-3.20-4.el7.noarch
200             perl-Text-ParseWords-3.29-4.el7.noarch
201             perl-Pod-Usage-1.63-3.el7.noarch
202             perl-threads-shared-1.43-6.el7.x86_64
203             perl-Filter-1.49-3.el7.x86_64
204             perl-Exporter-5.68-3.el7.noarch
205             ...
206              
207             =cut
208              
209             sub whatrequires {
210 0     0 1   my $self = shift;
211 0 0         my $capability = shift or die;
212 0           my $array = $self->_run3_array('--query' => '--whatrequires' => $capability);
213 0           return [map {RPM::Query::Package->new(package_name=>$_, parent=>$self)} uniq sort @$array];
  0            
214             }
215              
216             sub _run3_scalar {
217 0     0     my $self = shift;
218 0           my @argv = @_;
219 0           my $stdout = '';
220 0           my $error = 0;
221 0           IPC::Run3::run3 [$self->command => @argv], \undef, \$stdout, \$error;
222 0 0         die("Error: Command returned $error") if $error;
223 0           $stdout =~ s/\s+\Z//; #RTRIM
224 0           return $stdout;
225             }
226              
227             sub _run3_array {
228 0     0     my $self = shift;
229 0           my @argv = @_;
230 0           my @stdout = ();
231 0           my $error = 0;
232 0           IPC::Run3::run3 [$self->command => @argv], \undef, \@stdout, \$error;
233 0           chomp @stdout;
234 0 0 0       @stdout = () if (@stdout == 1
      0        
235             and (
236             $stdout[0] =~ m/\Ano package provides /
237             or
238             $stdout[0] =~ m/\Ano package requires /
239             or
240             $stdout[0] =~ m/\Apackage .* is not installed\Z/
241             )
242             );
243 0 0         die("Error: Command returned $error") if $error;
244 0           return \@stdout;
245             }
246              
247             sub _run3_error {
248 0     0     my $self = shift;
249 0           my @argv = @_;
250 0           my $error = 0;
251 0           IPC::Run3::run3 [$self->command => @argv], \undef, \undef, \$error;
252 0           return $error;
253             }
254              
255             =head1 PROPERTIES
256              
257             =head2 command
258              
259             =cut
260              
261             sub command {
262 0     0 1   my $self = shift;
263 0 0         $self->{'command'} = shift if @_;
264 0 0         $self->{'command'} = 'rpm' unless defined $self->{'command'};
265 0           return $self->{'command'};
266             }
267              
268             =head1 SEE ALSO
269              
270             =head1 AUTHOR
271              
272             Michael R. Davis
273              
274             =head1 COPYRIGHT AND LICENSE
275              
276             MIT License
277              
278             Copyright (c) 2023 Michael R. Davis
279              
280             =cut
281              
282             1;