Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

How to parse the zypper info output?

by ovedpo15 (Pilgrim)
on Dec 25, 2021 at 19:35 UTC ( [id://11139890]=perlquestion: print w/replies, xml ) Need Help??

ovedpo15 has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks!
I have a utility which iterates over a set of OS packages and finds the Zypper repo's name (using zypper info) and then it's URI and name (using zypper repos). The code looks like:
while(my ($package) = keys(%found_packages)) { delete($found_packages{$package}); # Ignore already handled packages next if (defined($checked_packages{$package})); $checked_packages{$package} = 1; # Find the zypper information of the OS package my $cmd = "$ZYPPER info $package"; my ($stdout, $stderr, $exit_status) = capture { system($cmd); }; if ($exit_status == 0 && $stdout =~ /^Repository\s*:\s*(\S+)\s*$/m) +{ my $repository_name = $1; if ($repository_name eq '@System') { if (defined($packages_href->{$repository_name})) { $packages_href->{$repository_name}{'packages'}{$package}++; } else { $packages_href->{$repository_name} = { 'packages' => { $package => 1 } }; } } else { if (defined($packages_href->{$repository_name})) { $packages_href->{$repository_name}{'packages'}{$package}++; } else { $cmd = "$ZYPPER repos -u $repository_name 2> $DEV_NULL"; ($stdout, $stderr, $exit_status) = capture { system($cmd); }; if ($exit_status) { print("Failed to find the information of the zypper reposito +ry: $repository_name"); } else { my $repository_alias = $1 if ($stdout =~ /^Alias\s*:\s*(\S+) +\s*$/m); my $repository_uri = $1 if ($stdout =~ /^URI\s*:\s*(\S+)\s +*$/m); if (is_empty_str($repository_alias) || is_empty_str($reposit +ory_uri)) { print("Failed to find the uri or alias of the zypper repos +itory: $repository_name"); next; } $packages_href->{$repository_name} = { 'alias' => $repository_alias, 'uri' => $repository_uri, 'packages' => { $package => 1 } }; } } } } }
I noticed that the invokation of the "zyyper info" command is really slow. I also noticed that you can provide a list of packages and it will print the output for each one. For example:
$ /usr/bin/zypper info python-rpm-macros Mesa-libEGL1 libedit0 fontcon +fig-devel Loading repository data... Reading installed packages... Information for package python-rpm-macros: ------------------------------------------ Repository : prod-sdk12-sp5-pool-x86_64-hpc Name : python-rpm-macros Version : 20200207.5feb6c1-3.19.1 Arch : noarch Vendor : SUSE LLC <https://www.suse.com/> Support Level : unknown Installed Size : 51.6 KiB Installed : Yes (automatically) Status : up-to-date Source package : python-rpm-macros-20200207.5feb6c1-3.19.1.src Summary : RPM macros for building of Python modules Description : This package contains SUSE RPM macros for Python build automation. You should BuildRequire this package unless you are sure that you are only building for distros newer than Leap 42.2 Information for package Mesa-libEGL1: ------------------------------------- Repository : prod-sp5-pool-x86_64-hpc Name : Mesa-libEGL1 Version : 18.3.2-14.3.2 Arch : x86_64 Vendor : SUSE LLC <https://www.suse.com/> Support Level : unknown Installed Size : 196.9 KiB Installed : Yes (automatically) Status : up-to-date Source package : Mesa-18.3.2-14.3.2.src Summary : EGL API implementation Description : This package contains the EGL native platform graphics interface library. EGL provides a platform-agnostic mechanism for creating rendering surfaces for use with other graphics libraries, such as OpenGL|ES and OpenVG. This package contains modules to interface with the existing syste +m GLX or DRI2 drivers to provide OpenGL via EGL. The Mesa main packa +ge provides drivers to provide hardware-accelerated OpenGL|ES and Ope +nVG support. Information for package libedit0: --------------------------------- Repository : prod-sp5-pool-x86_64-hpc Name : libedit0 Version : 3.1.snap20140620-1.13 Arch : x86_64 Vendor : SUSE LLC <https://www.suse.com/> Support Level : unknown Installed Size : 248.8 KiB Installed : Yes (automatically) Status : up-to-date Source package : libedit-3.1.snap20140620-1.13.src Summary : Command Line Editing and History Library Description : libedit is a command line editing and history library. It is desig +ned to be used by interactive programs that allow the user to type com +mands at a terminal prompt. Information for package fontconfig-devel: ----------------------------------------- Repository : prod-sdk12-sp5-pool-x86_64-hpc Name : fontconfig-devel Version : 2.11.1-7.1 Arch : x86_64 Vendor : SUSE LLC <https://www.suse.com/> Support Level : unknown Installed Size : 896.1 KiB Installed : Yes (automatically) Status : up-to-date Source package : fontconfig-2.11.1-7.1.src Summary : Include Files and Libraries mandatory for Development Description : This package countains all include files, libraries, configuration files needed for compiling applications which use the fontconfig library. In addition, it contains extensive documentation and manual pages +for developers using the library. Fontconfig is a library for configuring and customizing font acces +s. It contains two essential modules, the configuration module which bui +lds an internal configuration from XML files and the matching module w +hich accepts font patterns and returns the nearest matching font.
I'm trying to add the whole list of packages into the zypper info command and then iterate over each such block and extract the repository name and on each such name get the alias and URI. I'm struggling with the parsing part. Is it possible to get a suggestion on a how to parse the output of zypper info?

Replies are listed 'Best First'.
Re: How to parse the zypper info output?
by choroba (Cardinal) on Dec 25, 2021 at 21:15 UTC
    Zypper has a nice feature: you can use the -x option to get the output formatted as XML. Unfortunately, it doesn't help much for info (it just wraps each package into an element), but the output of lr is much nicer and easily parsable.
    #!/usr/bin/perl use warnings; use strict; use feature qw{ say }; use XML::LibXML; my %repos; open my $lr, '-|', qw{ zypper -x lr }; my $dom = 'XML::LibXML'->load_xml(IO => $lr); for my $repo ($dom->findnodes('/stream/repo-list/repo')) { $repos{ $repo->{name} } = {alias => $repo->{alias}, url => $repo->findvalue('url')}; } open my $zypper, '-|', qw{ zypper info python-rpm-macros Mesa-libEGL1 libedit0 fontconfig-dev +el } or die $!; my ($package, $repository); while (<$zypper>) { if (/^Information for package (.*):/) { $package = $1; } elsif (/Repository\s+: (\S+)/) { $repository = $1; say join "\t", $package, $repository, @{ $repos{$repository} }{qw{ alias url }}; } }

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: How to parse the zypper info output?
by kcott (Archbishop) on Dec 25, 2021 at 23:28 UTC

    G'day ovedpo15,

    "I'm trying to add the whole list of packages ... and then iterate over each such block and extract the repository name ... I'm struggling with the parsing part. Is it possible to get a suggestion on a how to parse the output of zypper info?"

    Redirect the output of your zypper info command to a file; e.g.

    $ /usr/bin/zypper info ... > info.out

    Then this code

    #!/usr/bin/env perl use strict; use warnings; use autodie; my $file = 'info.out'; my %repo_for; { open my $fh, '<', $file; local $/ = "\nInformation for package "; while (<$fh>) { next unless /\A([^:]+).*?Repository\s+:\s(\S+)/ms; $repo_for{$1} = $2; } } # For demo use Data::Dump; dd \%repo_for;

    will output:

    { "fontconfig-devel" => "prod-sdk12-sp5-pool-x86_64-hpc", "libedit0" => "prod-sp5-pool-x86_64-hpc", "Mesa-libEGL1" => "prod-sp5-pool-x86_64-hpc", "python-rpm-macros" => "prod-sdk12-sp5-pool-x86_64-hpc", }

    See $/ for details about how that works.

    — Ken

Re: How to parse the zypper info output?
by perlfan (Vicar) on Dec 27, 2021 at 16:05 UTC
    Maybe go to the source data? I was hoping to find an sqlite DB under the hood, but this is the closest I found to any package DB; and this doesn't look any worse than the zypper info output or the XML, https://github.com/openSUSE/zypper/blob/master/tests/data/openSUSE-11.1/suse/setup/descr/packages.gz - I couldn't find the descriptions and this might be very outdated; so, ymmv:
    ##---------------------------------------- =Pkg: perl-Net-DNS 0.62 4.1 i586 =Cks: SHA1 21e4716e48ea345bf53df78b55fdd6d147d8ebf2 +Req: perl-Digest-HMAC perl-Net-IP perl = 5.10.0 rpmlib(PayloadFilesHavePrefix) <= 4.0-1 rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(VersionedDependencies) <= 3.0.3-1 libc.so.6 libc.so.6(GLIBC_2.1.3) libc.so.6(GLIBC_2.4) rpmlib(PayloadIsBzip2) <= 3.0.5-1 -Req: +Prq: rpmlib(PayloadFilesHavePrefix) <= 4.0-1 rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(VersionedDependencies) <= 3.0.3-1 rpmlib(PayloadIsBzip2) <= 3.0.5-1 -Prq: +Prv: perl_dns DNS.so perl(Net::DNS) = 0.62 perl(Net::DNS::Header) = 622 perl(Net::DNS::Nameserver) = 688 perl(Net::DNS::Packet) = 688 perl(Net::DNS::Question) = 690 perl(Net::DNS::RR) = 688 perl(Net::DNS::RR::A) = 546 perl(Net::DNS::RR::AAAA) = 388 perl(Net::DNS::RR::AFSDB) = 632 perl(Net::DNS::RR::CERT) = 388 perl(Net::DNS::RR::CNAME) = 632 perl(Net::DNS::RR::DNAME) = 388 perl(Net::DNS::RR::EID) = 388 perl(Net::DNS::RR::HINFO) = 639 perl(Net::DNS::RR::IPSECKEY) = 654 perl(Net::DNS::RR::ISDN) = 388 perl(Net::DNS::RR::LOC) = 388 perl(Net::DNS::RR::MB) = 632 perl(Net::DNS::RR::MG) = 632 perl(Net::DNS::RR::MINFO) = 632 perl(Net::DNS::RR::MR) = 632 perl(Net::DNS::RR::MX) = 632 perl(Net::DNS::RR::NAPTR) = 583 perl(Net::DNS::RR::NIMLOC) = 388 perl(Net::DNS::RR::NS) = 632 perl(Net::DNS::RR::NSAP) = 388 perl(Net::DNS::RR::NULL) = 388 perl(Net::DNS::RR::OPT) = 393 perl(Net::DNS::RR::PTR) = 632 perl(Net::DNS::RR::PX) = 632 perl(Net::DNS::RR::RP) = 632 perl(Net::DNS::RR::RT) = 632 perl(Net::DNS::RR::SOA) = 632 perl(Net::DNS::RR::SPF) = 684 perl(Net::DNS::RR::SRV) = 583 perl(Net::DNS::RR::SSHFP) = 626 perl(Net::DNS::RR::TKEY) = 388 perl(Net::DNS::RR::TSIG) = 388 perl(Net::DNS::RR::TXT) = 582 perl(Net::DNS::RR::Unknown) = 388 perl(Net::DNS::RR::X25) = 388 perl(Net::DNS::Resolver) = 614 perl(Net::DNS::Resolver::Base) = 698 perl(Net::DNS::Resolver::Cygwin) = 696 perl(Net::DNS::Resolver::Recurse) = 591 perl(Net::DNS::Resolver::UNIX) = 482 perl(Net::DNS::Resolver::Win32) = 588 perl(Net::DNS::Update) = 517 perl-Net-DNS = 0.62-4.1 -Prv: +Obs: perl_dns -Obs: =Grp: Development/Libraries/Perl =Lic: Artistic License; GPL v2 or later =Src: perl-Net-DNS 0.62 4.1 src =Tim: 1202709958 =Loc: 1 perl-Net-DNS-0.62-4.1.i586.rpm =Siz: 258592 576685

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11139890]
Approved by marto
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (7)
As of 2024-04-23 11:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found