[Distutils] SOLVED: bdist_rpm and pre-release python packages / eggs (was: pre-release versioning problems with sdist, bdist_rpm, bdist_debian)

Bill Campbell distutils at celestial.com
Fri Mar 13 18:05:44 CET 2009

On Fri, Mar 13, 2009, Gerry Reno wrote:
> Manuel,
>  'bdist_rpm' is NOT broken.  What is broken is packagers misuse of the  
> 'version' and 'release' strings.  They do stupid things like put  
> version='3.0' and release='rc1' and then wonder why their final release  
> cannot update the release candidate.  THIS IS A TRAINING ISSUE...

This is a pretty good description of the cause of the problem,
but doesn't address a solution that may be used in software.

I deal mostly with building RPMs used under the OpenPKG portable
package management system which generally uses sane naming
conventions, at least as far as the release designations while
versions depend on the original package versions.

The attached bit of code is basically what we use to determine
the most recent packages, and works by splitting the version and
release into tuples of numeric and non-numeric parts, then
comparing these tuples.  This is based on a recipe in the
O'Reilly Python Cookbook to sort file names containing numerics.

This seems to solve most of the problems of sorting RPM packages
on version and release, but might fail in places where there are
issues of case-sensitivity.

INTERNET:   bill at celestial.com  Bill Campbell; Celestial Software LLC
URL: http://www.celestial.com/  PO Box 820; 6641 E. Mercer Way
Voice:          (206) 236-1676  Mercer Island, WA 98040-0820
Fax:            (206) 232-9186

During times of universal deceit, telling the truth becomes
a revolutionary act.  --George Orwell
-------------- next part --------------
# Class to facilitate sorting RPM packages based on version and
# release by splitting the version and release into tuples with
# numeric and non-numeric parts.
# This is based on code from the O'Reilly Python Cookbook, which
# I don't have handy to cite the page number.
import os, re

rpmcmd  = '/bin/rpm'
_fmt    = r"--queryformat='%{NAME}:%{VERSION}:%{RELEASE}:%{ARCH}\n'"
_digits = re.compile(r'(\d+)');

class RPM(object):
    def _ver(self, s):
        parts = []
        for part in s.split('.'):
            r = _digits.split(part)
            r[1::2] = [int(p) for p in r[1::2]]


    def __init__(self, file=None, name=None, query=None):
        if not query:
            if file:
                cmd = '%s -qp %s %s' % (rpmcmd, _fmt, file)
                self.file = file
                cmd = '%s -q %s %s' % (rpmcmd, _fmt, name)
                self.file = 'installed'

            fh = os.popen(cmd)
            query = fh.readline().strip()

        self.query = query
        (self.name, version, release, self.arch) = query.split(':')
        self._version = version
        self._release = release
        self.version = self._ver(version)
        self.release = self._ver(release)
        self.ver_rel = (self.version, self.release)

    def __cmp__(self, other):
        assert isinstance(other, RPM)
        return(cmp(self.ver_rel, other.ver_rel))

if __name__ == '__main__':
    print 'OK';
    print rpmcmd
    print _fmt
    rpm = RPM(name='python')
    print rpm.query;
    print rpm.name
    print rpm.version
    print rpm.release
    print rpm.ver_rel
    print rpm.arch
    print rpm.__cmp__(rpm)

More information about the Distutils-SIG mailing list