Parse an RPM name into its components

Solution 1:

You don't need to do any of this; RPM has a query format argument which will let you specify exactly the data you want to receive. It will even output without line endings if you don't specify them.

For instance:

rpm --queryformat "%{NAME} %{VERSION} %{RELEASE} %{ARCH}" -q coreutils
rpm --queryformat "The version of %{NAME} is %{VERSION}\n" -q coreutils

rpm --queryformat "%{NAME} %{VERSION} %{RELEASE} %{ARCH}" -qp file.rpm

The complete list of variables you can use can be obtained with:

rpm --querytags

Note that in the case of RELEASE, output like 84.el6 is normal and expected, since this is actually how RPM packages are versioned when packaged by or for a distribution.

Solution 2:

I've been told the official way to do what I'm seeking is in Python:

from rpmUtils.miscutils import splitFilename

(n, v, r, e, a) = splitFilename(filename)

I've written a short Python program that does what I need. I will offer the script to the rpmdev project for inclusion.

Solution 3:

I worked out regular expressions that fit all the data I was able to test them with. I had to use a mixture of greedy and non-greedy matches. That said, here is my perl and python versions:

Perl:

#! /usr/bin/perl

foreach (@ARGV) {
    ($path, $name, $version, $release, $platform,
      @junk) = m#(.*/)*(.*)-(.*)-(.*?)\.(.*)(\.rpm)#;
    $verrel = $version . '-' . $release;

    print join("\t", $path, $name, $verrel, $version, $rev, $platform), "\n";
}

Python:

#! /usr/bin/python

import sys
import re

for x in sys.argv[1:]:
    m = re.search(r'(.*/)*(.*)-(.*)-(.*?)\.(.*)(\.rpm)', x)
    if m:
        (path, name, version, release, platform, _) = m.groups()
        path = path or ''
        verrel = version + '-' + release
        print "\t".join([path, name, verrel, version, release, platform])
    else:
        sys.stderr.write('ERROR: Invalid name: %s\n' % x)
        sys.exit(1)

I'd rather have a regex that comes from the RPM project. The one that I invented above will have to do do for now.

Solution 4:

Rpm files can have some funky file names in extreme cases, but generally you can split the NVR on the hyphens. The catch is the N (name) portion of the NVR may contain hyphens and underscores, but the V(version) and R(release) are guaranteed to not have any extraneous hyphens. So you can start by trimming off the VR portion to derive a Name.

$ RPM=/home/builder/packages/testing-dev/CentOS/6/x86_64/emacs-mercurial-2.8-3.el6.x86_64.rpm
$ echo ${RPM%-*-*}
/home/builder/packages/testing-dev/CentOS/6/x86_64/emacs-mercurial

Building on that you can isolate the Version and Release portion.

echo ${RPM#${RPM%-*-*}-*}
2.8-3.el6.x86_64.rpm

Just split the hyphen again to isolate the part you need. And obviously clean out the arch and rpm file extension strings, which is a given. Just giving you an idea of how it could be approached in bash.

Solution 5:

Use the -q --queryformat options from rpm as said before, if you want to do this on a non installed package you can specify the rpm with the -p option, like this:

rpm -q -p ./Downloads/polysh-0.4-1.noarch.rpm --queryformat "%{NAME} %{VERSION} %{RELEASE} %{ARCH}\n"
polysh 0.4 1 noarch

e.g.

$ ls ./Downloads/*.rpm
./Downloads/adobe-release-x86_64-1.0-1.noarch.rpm
./Downloads/nautilus-dropbox-1.6.0-1.fedora.x86_64.rpm
./Downloads/playonlinux-yum-4-1.noarch.rpm
./Downloads/skype-4.2.0.11-fedora.i586.rpm
./Downloads/dbview-1.0.4-2.1.x86_64.rpm
./Downloads/openmotif22-libs-2.2.4-192.1.3.x86_64.rpm
./Downloads/polysh-0.4-1.noarch.rpm

gives me

adobe-release-x86_64 1.0 1 noarch
dbview 1.0.4 2.1 x86_64
nautilus-dropbox 1.6.0 1.fc10 x86_64
openmotif22-libs 2.2.4 192.1.3 x86_64
playonlinux-yum 4 1 noarch
polysh 0.4 1 noarch
skype 4.2.0.11 fc16 i586

so just splitting the filename is wrong!

for filename in """<paste list here>""".split():
    print splitFilename(filename)

('./Downloads/adobe-release-x86_64', '1.0', '1', '', 'noarch')
('./Downloads/nautilus-dropbox', '1.6.0', '1.fedora', '', 'x86_64')
('./Downloads/playonlinux-yum', '4', '1', '', 'noarch')
('./Downloads/skype', '4.2.0.11', 'fedora', '', 'i586')
('./Downloads/dbview', '1.0.4', '2.1', '', 'x86_64')
('./Downloads/openmotif22-libs', '2.2.4', '192.1.3', '', 'x86_64')
('./Downloads/polysh', '0.4', '1', '', 'noarch')

so pay attention, this is not the correct details of the rpm, e.g. 1.fedora is actually 1.fc10 in the rpm.