[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Updated dh_python to satisfy everybody



On Tue, 20 Jun 2006, Raphael Hertzog wrote:
> On Tue, 20 Jun 2006, Raphael Hertzog wrote:
> > On Mon, 19 Jun 2006, Raphael Hertzog wrote:
> > > - pyversions needs to be modified to not fail if the field
> > >   XS-Python-Version is not present. He should in that case
> > >   use the information of the debian/pyversions file. I will
> > >   hopefully soon provide a patch for this.
> > 
> > Here's a patch and the resulting pyversions script. For packages not using
> > XS-Python-Version, they can do "pyversions -r debian/pyversions" and get
> > the list of python packages to build with.
> 
> I've slightly updated the patch so that if someone is doing "pyversions -r
> debian/control" and if it would fail, then it tries "debian/pyversions"
> before failing.

Okay yet another update (the last... I promise). Instead of requiring a
parameter you can now call "pyversions -r" and in that case it will check
first for the field in debian/control and then try with debian/pyversions
and if nothing is found, then it will return all the supported versions.

Updated files attached.

Matthias, this time you can safely integrate this version in the official
python package.

Cheers,
-- 
Raphaël Hertzog

Premier livre français sur Debian GNU/Linux :
http://www.ouaza.com/livre/admin-debian/
--- /usr/bin/pyversions	2006-06-16 15:00:46.000000000 +0200
+++ pyversions	2006-06-20 09:40:55.000000000 +0200
@@ -116,6 +116,36 @@
     else:
         return ['python%s' % v for v in versions]
 
+def version_cmp(ver1,ver2):
+    v1=[int(i) for i in ver1.split('.')]
+    v2=[int(i) for i in ver2.split('.')]
+    return cmp(v1,v2)
+
+def requested_versions_bis(vstring, version_only=False):
+    versions = []
+    py_supported_short = supported_versions(version_only=True)
+    for item in vstring.split(','):
+        v=item.split('-')
+        if len(v)>1:
+            if not v[0]:
+                v[0] = py_supported_short[0]
+            if not v[1]:
+                v[1] = py_supported_short[-1]
+            for ver in py_supported_short:
+                try:
+                    if version_cmp(ver,v[0]) >= 0 and version_cmp(ver,v[1]) <= 0:
+                        versions.append(ver)
+                except ValueError:
+                    pass
+        else:
+            if v[0] in py_supported_short:
+                versions.append(v[0])
+    versions.sort(version_cmp)
+    if not version_only:
+        versions=['python'+i for i in versions]
+    return versions
+
+
 def installed_versions(version_only=False):
     import glob
     supported = supported_versions()
@@ -173,7 +203,7 @@
                       action='store_true', dest='supported')
     parser.add_option('-r', '--requested',
                       help='print the python versions requested by a build; the argument is either the name of a control file or the value of the XS-Python-Version attribute',
-                      action='store', dest='versions')
+                      action='store_true', dest='requested')
     parser.add_option('-i', '--installed',
                       help='print the installed supported python versions',
                       action='store_true', dest='installed')
@@ -189,13 +219,35 @@
         print ' '.join(supported_versions(opts.version_only))
     elif opts.installed:
         print ' '.join(installed_versions(opts.version_only))
-    elif opts.versions:
+    elif opts.requested:
         try:
-            if os.path.isfile(opts.versions):
-                vs = extract_pyversion_attribute(opts.versions, 'Source')
+            if len(args) >= 1:
+        	# Use parameters to find out the requested version
+        	if os.path.isfile(args[0]):
+        	    if args[0].find("pyversions") != -1:
+        		vs = file(args[0]).readline().rstrip('\n');
+        		print ' '.join(requested_versions_bis(vs, opts.version_only))
+        	    else:
+        		vs = extract_pyversion_attribute(args[0], 'Source')
+        		print ' '.join(requested_versions(vs, opts.version_only))
+        	else:
+        	    print ' '.join(requested_versions(args[0], opts.version_only))
             else:
-                vs = opts.versions
-            print ' '.join(requested_versions(vs, opts.version_only))
+        	# Check debian/control and debian/pyversions to find out
+        	# requestd versions
+        	done = 0
+        	if os.path.isfile("debian/control"):
+        	    try:
+        		vs = extract_pyversion_attribute("debian/control", 'Source')
+        		print ' '.join(requested_versions(vs, opts.version_only))
+        		done = 1
+        	    except:
+        		pass
+        	if not done and os.path.isfile("debian/pyversions"):
+        	    vs = file("debian/pyversions").readline().rstrip('\n');
+        	    print ' '.join(requested_versions_bis(vs, opts.version_only))
+        	elif not done:
+        	    print ' '.join(supported_versions(opts.version_only))
         except ValueError, msg:
             print "%s: %s" % (program, msg)
             sys.exit(1)
#! /usr/bin/python

import os, re, sys
try:
    SetType = set
except NameError:
    import sets
    SetType = sets.Set
    set = sets.Set

def parse_versions(vstring):
    import operator
    operators = { None: operator.eq, '=': operator.eq,
                  '>=': operator.ge, '<=': operator.le,
                  '<<': operator.lt
                  }
    vinfo = {}
    exact_versions = set([])
    version_range = set(supported_versions(version_only=True))
    relop_seen = False
    for field in vstring.split(','):
        field = field.strip()
        if field == 'all':
            vinfo['all'] = 'all'
            continue
        if field in ('current', 'current_ext'):
            vinfo['current'] = field
            continue
        vinfo.setdefault('versions', set())
        ve = re.compile('(>=|<=|<<|=)? *(\d\.\d)$')
        m = ve.match(field)
        try:
            op, v = m.group(1), m.group(2)
            if op in (None, '='):
                exact_versions.add(v)
            else:
                relop_seen = True
                filtop = operators[op]
                version_range = [av for av in version_range if filtop(av ,v)]
        except Exception:
            raise ValueError, 'error parsing Python-Version attribute'
    if 'versions' in vinfo:
        vinfo['versions'] = exact_versions
        if relop_seen:
            vinfo['versions'] = exact_versions.union(version_range)
    return vinfo

_supported_versions = None
def supported_versions(version_only=False):
    global _supported_versions
    if not _supported_versions:
        if os.path.exists('/usr/share/python/debian_defaults'):
            from ConfigParser import SafeConfigParser
            config = SafeConfigParser()
            config.readfp(file('/usr/share/python/debian_defaults'))
            value = config.get('DEFAULT', 'supported-versions')
            _supported_versions = [s.strip() for s in value.split(',')]
        else:
            cmd = ['/usr/bin/apt-cache', '--no-all-versions',
                   'show', 'python-all']
            try:
                import subprocess
                p = subprocess.Popen(cmd, bufsize=1,
                                     shell=False, stdout=subprocess.PIPE)
                fd = p.stdout
            except ImportError:
                fd = os.popen(' '.join(cmd))
            depends = None
            for line in fd:
                if line.startswith('Depends:'):
                    depends = line.split(':', 1)[1].strip().split(',')
            fd.close()
            depends = [re.sub(r'\s*(\S+)[ (]?.*', r'\1', s) for s in depends]
            _supported_versions = depends
    if version_only:
        return [v[6:] for v in _supported_versions]
    else:
        return _supported_versions

_default_version = None
def default_version(version_only=False):
    global _default_version
    if not _default_version:
        _default_version = link = os.readlink('/usr/bin/python')
    if version_only:
        return _default_version[6:]
    else:
        return _default_version

def requested_versions(vstring, version_only=False):
    versions = None
    vinfo = parse_versions(vstring)
    supported = supported_versions(version_only=True)
    if len(vinfo) == 1:
        if 'all' in vinfo:
            versions = supported
        elif 'current' in vinfo:
            versions = [default_version(version_only=True)]
        else:
            versions = vinfo['versions'].intersection(supported)
    elif 'all' in vinfo and 'current' in vinfo:
        raise ValueError, "both `current' and `all' in version string"
    elif 'all' in vinfo:
        versions = versions = vinfo['versions'].intersection(supported)
    elif 'current' in vinfo:
        current = default_version(version_only=True)
        if not current in vinfo['versions']:
            raise ValueError, "`current' version not in supported versions"
        versions = [current]
    else:
        raise ValueError, 'error in version string'
    if not versions:
        raise ValueError, 'empty set of versions'
    if version_only:
        return versions
    else:
        return ['python%s' % v for v in versions]

def version_cmp(ver1,ver2):
    v1=[int(i) for i in ver1.split('.')]
    v2=[int(i) for i in ver2.split('.')]
    return cmp(v1,v2)

def requested_versions_bis(vstring, version_only=False):
    versions = []
    py_supported_short = supported_versions(version_only=True)
    for item in vstring.split(','):
        v=item.split('-')
        if len(v)>1:
            if not v[0]:
                v[0] = py_supported_short[0]
            if not v[1]:
                v[1] = py_supported_short[-1]
            for ver in py_supported_short:
                try:
                    if version_cmp(ver,v[0]) >= 0 and version_cmp(ver,v[1]) <= 0:
                        versions.append(ver)
                except ValueError:
                    pass
        else:
            if v[0] in py_supported_short:
                versions.append(v[0])
    versions.sort(version_cmp)
    if not version_only:
        versions=['python'+i for i in versions]
    return versions


def installed_versions(version_only=False):
    import glob
    supported = supported_versions()
    versions = [os.path.basename(s)
                for s in glob.glob('/usr/bin/python[0-9].[0-9]')
                if os.path.basename(s) in supported]
    versions.sort()
    if version_only:
        return [v[6:] for v in versions]
    else:
        return versions

def extract_pyversion_attribute(fn, pkg):
    """read the debian/control file, extract the XS-Python-Version
    field; check that XB-Python-Version exists for the package."""

    version = None
    sversion = None
    section = None
    for line in file(fn):
        line = line.strip()
        if line == '':
            section = None
        elif line.startswith('Source:'):
            section = 'Source'
        elif line.startswith('Package: ' + pkg):
            section = self.name
        elif line.startswith('XS-Python-Version:'):
            if section != 'Source':
                raise ValueError, \
                      'attribute XS-Python-Version not in Source section'
            sversion = line.split(':', 1)[1].strip()
        elif line.startswith('XB-Python-Version:'):
            if section == pkg:
                version = line.split(':', 1)[1].strip()
    if pkg == 'Source':
        if sversion == None:
            raise ValueError, 'missing XS-Python-Version in control file'
        return sversion
    if version == None:
        raise ValueError, \
              'missing XB-Python-Version for package `%s' % pkg
    return version


def main():
    from optparse import OptionParser
    usage = '[-v] [-h] [-d|--default] [-s|--supported] [-i|--installed] [-r|--requested <version string>|<control file>]'
    parser = OptionParser(usage=usage)
    parser.add_option('-d', '--default',
                      help='print the default python version',
                      action='store_true', dest='default')
    parser.add_option('-s', '--supported',
                      help='print the supported python versions',
                      action='store_true', dest='supported')
    parser.add_option('-r', '--requested',
                      help='print the python versions requested by a build; the argument is either the name of a control file or the value of the XS-Python-Version attribute',
                      action='store_true', dest='requested')
    parser.add_option('-i', '--installed',
                      help='print the installed supported python versions',
                      action='store_true', dest='installed')
    parser.add_option('-v', '--version',
                      help='print just the version number(s)',
                      default=False, action='store_true', dest='version_only')
    opts, args = parser.parse_args()
    program = os.path.basename(sys.argv[0])

    if opts.default:
        print default_version(opts.version_only)
    elif opts.supported:
        print ' '.join(supported_versions(opts.version_only))
    elif opts.installed:
        print ' '.join(installed_versions(opts.version_only))
    elif opts.requested:
        try:
            if len(args) >= 1:
        	# Use parameters to find out the requested version
        	if os.path.isfile(args[0]):
        	    if args[0].find("pyversions") != -1:
        		vs = file(args[0]).readline().rstrip('\n');
        		print ' '.join(requested_versions_bis(vs, opts.version_only))
        	    else:
        		vs = extract_pyversion_attribute(args[0], 'Source')
        		print ' '.join(requested_versions(vs, opts.version_only))
        	else:
        	    print ' '.join(requested_versions(args[0], opts.version_only))
            else:
        	# Check debian/control and debian/pyversions to find out
        	# requestd versions
        	done = 0
        	if os.path.isfile("debian/control"):
        	    try:
        		vs = extract_pyversion_attribute("debian/control", 'Source')
        		print ' '.join(requested_versions(vs, opts.version_only))
        		done = 1
        	    except:
        		pass
        	if not done and os.path.isfile("debian/pyversions"):
        	    vs = file("debian/pyversions").readline().rstrip('\n');
        	    print ' '.join(requested_versions_bis(vs, opts.version_only))
        	elif not done:
        	    print ' '.join(supported_versions(opts.version_only))
        except ValueError, msg:
            print "%s: %s" % (program, msg)
            sys.exit(1)
    else:
        print "usage: %s %s" % (program, usage)
        sys.exit(1)

if __name__ == '__main__':
    main()

Reply to: