lsb 3.2-21 Debian release.
authorChris Lawrence <lawrencc@debian.org>
Thu, 19 Mar 2009 21:29:25 +0000 (16:29 -0500)
committerDidier Raboud <odyx@debian.org>
Thu, 19 Mar 2009 21:29:25 +0000 (16:29 -0500)
debian/changelog
debian/compat
debian/control
debian/copyright
debian/lsb-release.dirs
debian/rules
init-functions
lsb_release
lsb_release.1
lsb_release.py [new file with mode: 0644]

index 799b29f0b38bb49c0c6a5e0a9577e2313302efd4..f4d39faef8f90f2de73b24a7502c9fe8983e458d 100644 (file)
@@ -1,3 +1,21 @@
+lsb (3.2-21) unstable; urgency=low
+
+  * Provide lsb_release module for Python applications.  (Closes: #486262)
+  * Change working directory to $PWD in start-stop-daemon, for better
+    compatibility with LSB applications.  (Closes: #519817)
+  * return 3 rather than 4 in pidofproc if a PID file is specified and
+    the daemon is not found.  (Closes: #494623)
+  * Improve handling of future testing versions unknown to lsb-release.
+    Patch by Jan Muszynski (Closes: #517594).
+  * Fix DeprecationWarning with Python 2.6; patch from Colin Watson and
+    Anders Kaseorg.  (Closes: #517819)
+  * Bypass guess_debian_release() if /etc/lsb-release is complete.
+    Patch from Scott James Remnant.  (Closes: #511952)
+  * 'time' was missing from lsb-core dependencies.  (Closes: #510488)
+  * Demote lsb to a suggestion by lsb-release.  (Closes: #509611)
+
+ -- Chris Lawrence <lawrencc@debian.org>  Thu, 19 Mar 2009 16:29:25 -0500
+
 lsb (3.2-20) unstable; urgency=low
 
   * Revert change in 3.2-16 that broke killproc due to my misunderstanding
index b8626c4cff2849624fb67f87cd0ad72b163671ad..7f8f011eb73d6043d2e6db9d2c101195ae2801f2 100644 (file)
@@ -1 +1 @@
-4
+7
index 68145265917214a376ca9903372498446459fb6d..9cad9fc30022ae5e5024b9eb2e7afd93e2079e75 100644 (file)
@@ -2,14 +2,14 @@ Source: lsb
 Section: misc
 Priority: extra
 Maintainer: Chris Lawrence <lawrencc@debian.org>
-Build-Depends: debhelper (>= 5.0.37.2), po-debconf (>= 0.5.0), dpkg-dev (>= 1.10), python-central (>= 0.5), python-all-dev
-Standards-Version: 3.8.0
+Build-Depends: debhelper (>> 7), po-debconf (>= 0.5.0), dpkg-dev (>= 1.10), python-support, python-all-dev
+Standards-Version: 3.8.1
 XS-Python-Version: current
 Homepage: http://www.linux-foundation.org/en/LSB
 
 Package: lsb-core
 Architecture: any
-Depends: lsb-release, ${glibc}, libz1, libncurses5, libpam0g, exim4 | mail-transport-agent, at, bc, binutils, bsdmainutils, bsdutils, cpio, cron, ed, file, libc6-dev | libc-dev, locales, lpr, lprng | cups-client, m4, mailx | mailutils, make, man-db, mawk | gawk, ncurses-term, passwd, patch, pax, procps, psmisc, rsync, alien (>= 8.36), ${python:Depends}, ${misc:Depends}, ${depends}, lsb-base
+Depends: lsb-release, ${glibc}, libz1, libncurses5, libpam0g, exim4 | mail-transport-agent, at, bc, binutils, bsdmainutils, bsdutils, cpio, cron, ed, file, libc6-dev | libc-dev, locales, lpr, lprng | cups-client, m4, mailx | mailutils, make, man-db, mawk | gawk, ncurses-term, passwd, patch, pax, procps, psmisc, rsync, alien (>= 8.36), ${python:Depends}, ${misc:Depends}, ${depends}, lsb-base, time
 Provides: lsb-core-noarch, ${provides}
 Conflicts: python (>= 2.6), lsb (<< 2.0-2)
 Replaces: lsb (<< 2.0-2)
@@ -97,7 +97,7 @@ Description: Linux Standard Base 3.2 Desktop support package
 
 Package: lsb-qt4
 Architecture: any
-Depends: lsb-desktop (>= 3.2)
+Depends: lsb-desktop (>= 3.2), ${misc:Depends}
 Provides: lsb-qt4-noarch, ${provides}
 Description: Linux Standard Base 3.2 Qt4 support package
  The Linux Standard Base (http://www.linuxbase.org/) is a standard
@@ -122,7 +122,7 @@ Description: Linux Standard Base 3.2 Qt4 support package
 
 Package: lsb-languages
 Architecture: any
-Depends: lsb-core (>= 3.2), python (>= 2.4), perl (>= 5.8.8), perl (<< 6)
+Depends: lsb-core (>= 3.2), python (>= 2.4), perl (>= 5.8.8), perl (<< 6), ${misc:Depends}
 Provides: lsb-languages-noarch, ${provides}
 Description: Linux Standard Base 3.2 Runtime Languages package
  The Linux Standard Base (http://www.linuxbase.org/) is a standard
@@ -143,7 +143,7 @@ Description: Linux Standard Base 3.2 Runtime Languages package
 
 Package: lsb-multimedia
 Architecture: any
-Depends: lsb-core (>= 3.2), libasound2
+Depends: lsb-core (>= 3.2), libasound2, ${misc:Depends}
 Provides: lsb-multimedia-noarch, ${provides}
 Description: Linux Standard Base 3.2 Multimedia package
  The Linux Standard Base (http://www.linuxbase.org/) is a standard
@@ -164,7 +164,7 @@ Description: Linux Standard Base 3.2 Multimedia package
 
 Package: lsb-printing
 Architecture: any
-Depends: lsb-core (>= 3.2), libcups2, libcupsimage2, foomatic-filters, ghostscript | gs
+Depends: lsb-core (>= 3.2), libcups2, libcupsimage2, foomatic-filters, ghostscript, ${misc:Depends}
 Provides: lsb-printing-noarch, ${provides}
 Description: Linux Standard Base 3.2 Printing package
  The Linux Standard Base (http://www.linuxbase.org/) is a standard
@@ -185,7 +185,7 @@ Description: Linux Standard Base 3.2 Printing package
 
 Package: lsb
 Architecture: all
-Depends: lsb-core, lsb-graphics, lsb-cxx, lsb-desktop
+Depends: lsb-core, lsb-graphics, lsb-cxx, lsb-desktop, ${misc:Depends}
 Suggests: lsb-printing, lsb-multimedia, lsb-languages
 Description: Linux Standard Base 3.2 support package
  The Linux Standard Base (http://www.linuxbase.org/) is a standard
@@ -206,7 +206,7 @@ Description: Linux Standard Base 3.2 support package
 
 Package: lsb-base
 Architecture: all
-Depends: sed, ncurses-bin
+Depends: sed, ncurses-bin, ${misc:Depends}
 Replaces: lsb-core (<< 2.0-6), lsb (<< 2.0-6)
 Conflicts: lsb-core (<< 2.0-6), lsb (<< 2.0-6)
 Priority: required
@@ -221,7 +221,7 @@ Description: Linux Standard Base 3.2 init script functionality
 
 Package: lsb-release
 Architecture: all
-Depends: ${python:Depends}
+Depends: ${python:Depends}, ${misc:Depends}
 Recommends: apt
 Suggests: lsb
 XB-Python-Version: ${python:Versions}
index a5eeaed5d2f1fcc36ac9e19c92ad37bd78e4b8d1..09e168b35c9681ef10a0c9df855aa2e4f1490cd9 100644 (file)
@@ -4,7 +4,7 @@ Sun, 17 Feb 2002 14:07:32 -0600.
 The HTML files in html/ were written by Matt Taggart <taggart@debian.org>
 
 Copyright:
-   Copyright © 2002-08 Chris Lawrence and Matt Taggart
+   Copyright © 2002-09 Chris Lawrence and Matt Taggart
 
    This package is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -21,12 +21,12 @@ Copyright:
    USA.
 
 On Debian systems, the complete text of the GNU General Public License
-can be found in `/usr/share/common-licenses/GPL'.
+can be found in `/usr/share/common-licenses/GPL-2'.
 
 The file /lib/lsb/init-functions is licensed under a permissive
 "BSD-style" license as follows:
 
-Copyright © 2002-08 Chris Lawrence
+Copyright © 2002-09 Chris Lawrence
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
index 2e451f550f53eda742c8d973038682554a62d094..8f49a8137bd837e58c01394ee87922c17230919b 100644 (file)
@@ -1,2 +1,3 @@
 usr/bin
 usr/share/bug
+usr/share/python-support/lsb-release
index dc344968188af7730d5282e1582ac1efff44998b..a804dbe2bb69f42e8624e8041c84c1dbcc16a47a 100755 (executable)
@@ -76,7 +76,7 @@ clean:
 install: build
        dh_testdir
        dh_testroot
-       dh_clean -k
+       dh_prep
        dh_installdirs
 
        # Add here commands to install the package into debian/lsb.
@@ -84,6 +84,7 @@ install: build
        cp -p initdutils.py install_initd remove_initd lsbinstall debian/lsb-core/usr/lib/lsb
        cp -p init-functions debian/lsb-base/lib/lsb
        cp -p lsb_release debian/lsb-release/usr/bin
+       cp -p lsb_release.py debian/lsb-release/usr/share/python-support/lsb-release
        cp -p debian/lsb-release.bugscript debian/lsb-release/usr/share/bug/lsb-release
 
 # Build architecture-independent files here.
@@ -107,10 +108,10 @@ binary-indep: build install
        dh_compress -i
        dh_fixperms -i
 #      dh_makeshlibs
-       dh_installdeb -i
 #      dh_perl
-       dh_pycentral
-       dh_python
+       dh_pysupport -i
+#      dh_python
+       dh_installdeb -i
        dh_shlibdeps -i
        dh_gencontrol -i
        dh_md5sums -i
@@ -149,6 +150,7 @@ binary-arch: build install
        dh_strip -a
        dh_compress -a
        dh_fixperms -a
+       dh_pysupport -a
 #      dh_makeshlibs
        dh_installdeb -a
 #      dh_perl
index 4d99df00340bf30655e45378025868448a969b56..f2da85f4fcee8eb907e9ca2bf0b9ba44b103d300 100644 (file)
@@ -28,7 +28,7 @@
 #EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 start_daemon () {
-    local force nice pidfile exec i
+    local force nice pidfile exec i args
     force=0
     nice=0
     pidfile=/dev/null
@@ -49,12 +49,13 @@ start_daemon () {
 
     exec="$1"; shift
 
+    args="--start --chdir '$PWD' --nicelevel $nice --quiet --oknodo"
     if [ $force = 1 ]; then
-        /sbin/start-stop-daemon --start --nicelevel $nice --quiet --startas $exec --pidfile /dev/null --oknodo -- "$@"
+        /sbin/start-stop-daemon $args --startas $exec --pidfile /dev/null -- "$@"
     elif [ $pidfile ]; then
-        /sbin/start-stop-daemon --start --nicelevel $nice --quiet --exec $exec --oknodo --pidfile "$pidfile" -- "$@"
+        /sbin/start-stop-daemon $args --exec $exec --oknodo --pidfile "$pidfile" -- "$@"
     else
-        /sbin/start-stop-daemon --start --nicelevel $nice --quiet --exec $exec --oknodo -- "$@"
+        /sbin/start-stop-daemon $args --exec $exec -- "$@"
     fi
 }
 
@@ -98,6 +99,9 @@ pidofproc () {
         fi
         return 0
     fi
+    if [ "$specified" ]; then
+        return 3 # program does not appear to be running after trying PID file
+    fi
     return 4 # program or service is unknown
 }
 
index 3f6c7f869f4bf78a5802804312a64e520c0a682f..0bec11cdd04bd17a9eacc19b1a8120fd3409e46f 100755 (executable)
@@ -23,228 +23,8 @@ import commands
 import os
 import re
 
-# XXX: Update as needed
-# This should really be included in apt-cache policy output... it is already
-# in the Release file...
-RELEASE_CODENAME_LOOKUP = {
-    '1.1' : 'buzz',
-    '1.2' : 'rex',
-    '1.3' : 'bo',
-    '2.0' : 'hamm',
-    '2.1' : 'slink',
-    '2.2' : 'potato',
-    '3.0' : 'woody',
-    '3.1' : 'sarge',
-    '4.0' : 'etch',
-    '5.0' : 'lenny',
-    }
+import lsb_release
 
-TESTING_CODENAME = 'lenny'
-
-def lookup_codename(release, unknown=None):
-    m = re.match(r'(\d+)\.(\d+)(r(\d+))?', release)
-    if not m:
-        return unknown
-
-    shortrelease = '%s.%s' % m.group(1,2)
-    return RELEASE_CODENAME_LOOKUP.get(shortrelease, unknown)
-
-# LSB compliance packages... may grow eventually
-PACKAGES = 'lsb-core lsb-cxx lsb-graphics lsb-desktop lsb-qt4 lsb-languages lsb-multimedia lsb-printing'
-
-modnamere = re.compile(r'lsb-(?P<module>[a-z0-9]+)-(?P<arch>[^ ]+)(?: \(= (?P<version>[0-9.]+)\))?')
-
-def valid_lsb_versions(version, module):
-    # If a module is ever released that only appears in >= version, deal
-    # with that here
-    if version == '3.0':
-        return ['2.0', '3.0']
-    elif version == '3.1':
-        if module in ('desktop', 'qt4'):
-            return ['3.1']
-        else:
-            return ['2.0', '3.0', '3.1']
-    elif version == '3.2':
-        if module == 'desktop':
-            return ['3.1', '3.2']
-        elif module == 'qt4':
-            return ['3.1']
-        elif module in ('printing', 'languages', 'multimedia'):
-            return ['3.2']
-        elif module == 'cxx':
-            return ['3.0', '3.1', '3.2']
-        else:
-            return ['2.0', '3.0', '3.1', '3.2']
-
-    return [version]
-
-import sets
-
-# This is Debian-specific at present
-def check_modules_installed():
-    # Find which LSB modules are installed on this system
-    output = commands.getoutput("dpkg-query -f '${Version} ${Provides}\n' -W %s 2>/dev/null" % PACKAGES)
-    if not output:
-        return []
-
-    modules = sets.Set()
-    for line in output.split(os.linesep):
-        version, provides = line.split(' ', 1)
-        version = version.split('-', 1)[0]
-        for pkg in provides.split(','):
-            mob = modnamere.search(pkg)
-            if not mob:
-                continue
-
-            mgroups = mob.groupdict()
-            # If no versioned provides...
-            if mgroups.get('version'):
-                module = '%(module)s-%(version)s-%(arch)s' % mgroups
-                modules.add(module)
-            else:
-                module = mgroups['module']
-                for v in valid_lsb_versions(version, module):
-                    mgroups['version'] = v
-                    module = '%(module)s-%(version)s-%(arch)s' % mgroups
-                    modules.add(module)
-
-    modules = list(modules)
-    modules.sort()
-    return modules
-
-longnames = {'v' : 'version', 'o': 'origin', 'a': 'suite',
-             'c' : 'component', 'l': 'label'}
-
-def parse_policy_line(data):
-    retval = {}
-    bits = data.split(',')
-    for bit in bits:
-        kv = bit.split('=', 1)
-        if len(kv) > 1:
-            k, v = kv[:2]
-            if k in longnames:
-                retval[longnames[k]] = v
-    return retval
-
-def parse_apt_policy():
-    data = []
-    
-    policy = commands.getoutput('apt-cache policy 2>/dev/null')
-    for line in policy.split('\n'):
-        line = line.strip()
-        m = re.match(r'(\d+)', line)
-        if m:
-            priority = int(m.group(1))
-        if line.startswith('release'):
-            bits = line.split(' ', 1)
-            if len(bits) > 1:
-                data.append( (priority, parse_policy_line(bits[1])) )
-
-    return data
-
-def guess_release_from_apt(origin='Debian', component='main',
-                           ignoresuites=('experimental'),
-                           label='Debian'):
-    releases = parse_apt_policy()
-
-    if not releases:
-        return None
-
-    # We only care about the specified origin, component, and label
-    releases = [x for x in releases if (
-        x[1].get('origin', '') == origin and
-        x[1].get('component', '') == component and
-        x[1].get('label', '') == label)]
-
-    # Check again to make sure we didn't wipe out all of the releases
-    if not releases:
-        return None
-    
-    releases.sort()
-    releases.reverse()
-
-    # We've sorted the list by descending priority, so the first entry should
-    # be the "main" release in use on the system
-
-    return releases[0][1]
-
-def guess_debian_release():
-    distinfo = {'ID' : 'Debian'}
-
-    kern = os.uname()[0]
-    if kern in ('Linux', 'Hurd', 'NetBSD'):
-        distinfo['OS'] = 'GNU/'+kern
-    elif kern == 'FreeBSD':
-        distinfo['OS'] = 'GNU/k'+kern
-    else:
-        distinfo['OS'] = 'GNU'
-
-    distinfo['DESCRIPTION'] = '%(ID)s %(OS)s' % distinfo
-
-    if os.path.exists('/etc/debian_version'):
-        release = open('/etc/debian_version').read().strip()
-        if not release[0:1].isalpha():
-            # /etc/debian_version should be numeric
-            codename = lookup_codename(release, 'n/a')
-            distinfo.update({ 'RELEASE' : release, 'CODENAME' : codename })
-        elif release.endswith('/sid'):
-            distinfo['RELEASE'] = 'testing/unstable'
-        else:
-            distinfo['RELEASE'] = release
-
-    # Only use apt information if we did not get the proper information
-    # from /etc/debian_version or if we don't have a codename
-    # (which will happen if /etc/debian_version does not contain a
-    # number but some text like 'testing/unstable' or 'lenny/sid')
-    #
-    # This is slightly faster and less error prone in case the user
-    # has an entry in his /etc/apt/sources.list but has not actually
-    # upgraded the system.
-    rinfo = guess_release_from_apt()
-    if rinfo and not distinfo.get('CODENAME'):
-        release = rinfo.get('version')
-        if release:
-            codename = lookup_codename(release, 'n/a')
-        else:
-            release = rinfo.get('suite', 'unstable')
-            if release == 'testing':
-                # Would be nice if I didn't have to hardcode this.
-                codename = TESTING_CODENAME
-            else:
-                codename = 'sid'
-        distinfo.update({ 'RELEASE' : release, 'CODENAME' : codename })
-
-    if distinfo.get('RELEASE'):
-        distinfo['DESCRIPTION'] += ' %(RELEASE)s' % distinfo
-    if distinfo.get('CODENAME'):
-        distinfo['DESCRIPTION'] += ' (%(CODENAME)s)' % distinfo
-
-    return distinfo
-
-# Whatever is guessed above can be overridden in /etc/lsb-release
-def get_lsb_information():
-    distinfo = {}
-    if os.path.exists('/etc/lsb-release'):
-        for line in open('/etc/lsb-release'):
-            line = line.strip()
-            if not line:
-                continue
-            # Skip invalid lines
-            if not '=' in line:
-                continue
-            var, arg = line.split('=', 1)
-            if var.startswith('DISTRIB_'):
-                var = var[8:]
-                if arg.startswith('"') and arg.endswith('"'):
-                    arg = arg[1:-1]
-                distinfo[var] = arg
-    return distinfo
-
-def get_distro_information():
-    distinfo = guess_debian_release()
-    distinfo.update(get_lsb_information())
-    return distinfo
-    
 def main():
     parser = OptionParser()
     parser.add_option('-v', '--version', dest='version', action='store_true',
@@ -274,14 +54,13 @@ def main():
         parser.error("No arguments are permitted")
 
     short = (options.short)
-    all = (options.all)
     none = not (options.all or options.version or options.id or
                 options.description or options.codename or options.release)
 
-    distinfo = get_distro_information()
+    distinfo = lsb_release.get_distro_information()
 
-    if none or all or options.version:
-        verinfo = check_modules_installed()
+    if none or options.all or options.version:
+        verinfo = lsb_release.check_modules_installed()
         if not verinfo:
             print >> sys.stderr, "No LSB modules are available."
         elif short:
@@ -289,25 +68,25 @@ def main():
         else:
             print 'LSB Version:\t' + ':'.join(verinfo)
 
-    if options.id or all:
+    if options.id or options.all:
         if short:
             print distinfo.get('ID', 'n/a')
         else:
             print 'Distributor ID:\t%s' % distinfo.get('ID', 'n/a')
 
-    if options.description or all:
+    if options.description or options.all:
         if short:
             print distinfo.get('DESCRIPTION', 'n/a')
         else:
             print 'Description:\t%s' % distinfo.get('DESCRIPTION', 'n/a')
 
-    if options.release or all:
+    if options.release or options.all:
         if short:
             print distinfo.get('RELEASE', 'n/a')
         else:
             print 'Release:\t%s' % distinfo.get('RELEASE', 'n/a')
 
-    if options.codename or all:
+    if options.codename or options.all:
         if short:
             print distinfo.get('CODENAME', 'n/a')
         else:
index eda206d50c69fcf00ab053c2ab282d20cff1d752..70dc43d9fa408385a11e5674f7b97030830dcad0 100644 (file)
@@ -47,6 +47,11 @@ This is a reimplementation of the
 .B lsb_release
 command provided by the Free Standards Group.  Any bugs are solely the
 responsibility of the author below.
+
+Detection of systems using a mix of packages from various distributions
+or releases is something of a black art; the current heuristic tends
+to assume that the installation is of the earliest distribution which
+is still being used by .B apt but that heuristic is subject to error.
 .SH "SEE ALSO"
 lsb(8)
 .SH AUTHOR
diff --git a/lsb_release.py b/lsb_release.py
new file mode 100644 (file)
index 0000000..7269322
--- /dev/null
@@ -0,0 +1,259 @@
+#!/usr/bin/python
+
+# LSB release detection module for Debian
+# (C) 2005-09 Chris Lawrence <lawrencc@debian.org>
+
+#    This package is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; version 2 dated June, 1991.
+
+#    This package is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+
+#    You should have received a copy of the GNU General Public License
+#    along with this package; if not, write to the Free Software
+#    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+#    02111-1307, USA.
+
+import sys
+import commands
+import os
+import re
+
+# XXX: Update as needed
+# This should really be included in apt-cache policy output... it is already
+# in the Release file...
+RELEASE_CODENAME_LOOKUP = {
+    '1.1' : 'buzz',
+    '1.2' : 'rex',
+    '1.3' : 'bo',
+    '2.0' : 'hamm',
+    '2.1' : 'slink',
+    '2.2' : 'potato',
+    '3.0' : 'woody',
+    '3.1' : 'sarge',
+    '4.0' : 'etch',
+    '5.0' : 'lenny',
+    }
+
+TESTING_CODENAME = 'unknown.new.testing'
+
+def lookup_codename(release, unknown=None):
+    m = re.match(r'(\d+)\.(\d+)(r(\d+))?', release)
+    if not m:
+        return unknown
+
+    shortrelease = '%s.%s' % m.group(1,2)
+    return RELEASE_CODENAME_LOOKUP.get(shortrelease, unknown)
+
+# LSB compliance packages... may grow eventually
+PACKAGES = 'lsb-core lsb-cxx lsb-graphics lsb-desktop lsb-qt4 lsb-languages lsb-multimedia lsb-printing'
+
+modnamere = re.compile(r'lsb-(?P<module>[a-z0-9]+)-(?P<arch>[^ ]+)(?: \(= (?P<version>[0-9.]+)\))?')
+
+def valid_lsb_versions(version, module):
+    # If a module is ever released that only appears in >= version, deal
+    # with that here
+    if version == '3.0':
+        return ['2.0', '3.0']
+    elif version == '3.1':
+        if module in ('desktop', 'qt4'):
+            return ['3.1']
+        else:
+            return ['2.0', '3.0', '3.1']
+    elif version == '3.2':
+        if module == 'desktop':
+            return ['3.1', '3.2']
+        elif module == 'qt4':
+            return ['3.1']
+        elif module in ('printing', 'languages', 'multimedia'):
+            return ['3.2']
+        elif module == 'cxx':
+            return ['3.0', '3.1', '3.2']
+        else:
+            return ['2.0', '3.0', '3.1', '3.2']
+
+    return [version]
+
+try:
+    set # introduced in 2.4
+except NameError:
+    import sets
+    set = sets.Set
+
+# This is Debian-specific at present
+def check_modules_installed():
+    # Find which LSB modules are installed on this system
+    output = commands.getoutput("dpkg-query -f '${Version} ${Provides}\n' -W %s 2>/dev/null" % PACKAGES)
+    if not output:
+        return []
+
+    modules = set()
+    for line in output.split(os.linesep):
+        version, provides = line.split(' ', 1)
+        version = version.split('-', 1)[0]
+        for pkg in provides.split(','):
+            mob = modnamere.search(pkg)
+            if not mob:
+                continue
+
+            mgroups = mob.groupdict()
+            # If no versioned provides...
+            if mgroups.get('version'):
+                module = '%(module)s-%(version)s-%(arch)s' % mgroups
+                modules.add(module)
+            else:
+                module = mgroups['module']
+                for v in valid_lsb_versions(version, module):
+                    mgroups['version'] = v
+                    module = '%(module)s-%(version)s-%(arch)s' % mgroups
+                    modules.add(module)
+
+    modules = list(modules)
+    modules.sort()
+    return modules
+
+longnames = {'v' : 'version', 'o': 'origin', 'a': 'suite',
+             'c' : 'component', 'l': 'label'}
+
+def parse_policy_line(data):
+    retval = {}
+    bits = data.split(',')
+    for bit in bits:
+        kv = bit.split('=', 1)
+        if len(kv) > 1:
+            k, v = kv[:2]
+            if k in longnames:
+                retval[longnames[k]] = v
+    return retval
+
+def parse_apt_policy():
+    data = []
+    
+    policy = commands.getoutput('apt-cache policy 2>/dev/null')
+    for line in policy.split('\n'):
+        line = line.strip()
+        m = re.match(r'(\d+)', line)
+        if m:
+            priority = int(m.group(1))
+        if line.startswith('release'):
+            bits = line.split(' ', 1)
+            if len(bits) > 1:
+                data.append( (priority, parse_policy_line(bits[1])) )
+
+    return data
+
+def guess_release_from_apt(origin='Debian', component='main',
+                           ignoresuites=('experimental'),
+                           label='Debian'):
+    releases = parse_apt_policy()
+
+    if not releases:
+        return None
+
+    # We only care about the specified origin, component, and label
+    releases = [x for x in releases if (
+        x[1].get('origin', '') == origin and
+        x[1].get('component', '') == component and
+        x[1].get('label', '') == label)]
+
+    # Check again to make sure we didn't wipe out all of the releases
+    if not releases:
+        return None
+    
+    releases.sort()
+    releases.reverse()
+
+    # We've sorted the list by descending priority, so the first entry should
+    # be the "main" release in use on the system
+
+    return releases[0][1]
+
+def guess_debian_release():
+    distinfo = {'ID' : 'Debian'}
+
+    kern = os.uname()[0]
+    if kern in ('Linux', 'Hurd', 'NetBSD'):
+        distinfo['OS'] = 'GNU/'+kern
+    elif kern == 'FreeBSD':
+        distinfo['OS'] = 'GNU/k'+kern
+    else:
+        distinfo['OS'] = 'GNU'
+
+    distinfo['DESCRIPTION'] = '%(ID)s %(OS)s' % distinfo
+
+    if os.path.exists('/etc/debian_version'):
+        release = open('/etc/debian_version').read().strip()
+        if not release[0:1].isalpha():
+            # /etc/debian_version should be numeric
+            codename = lookup_codename(release, 'n/a')
+            distinfo.update({ 'RELEASE' : release, 'CODENAME' : codename })
+        elif release.endswith('/sid'):
+            if release.rstrip('/sid').lower().isalpha() != 'testing':
+                global TESTING_CODENAME
+                TESTING_CODENAME = release.rstrip('/sid')
+            distinfo['RELEASE'] = 'testing/unstable'
+        else:
+            distinfo['RELEASE'] = release
+
+    # Only use apt information if we did not get the proper information
+    # from /etc/debian_version or if we don't have a codename
+    # (which will happen if /etc/debian_version does not contain a
+    # number but some text like 'testing/unstable' or 'lenny/sid')
+    #
+    # This is slightly faster and less error prone in case the user
+    # has an entry in his /etc/apt/sources.list but has not actually
+    # upgraded the system.
+    rinfo = guess_release_from_apt()
+    if rinfo and not distinfo.get('CODENAME'):
+        release = rinfo.get('version')
+        if release:
+            codename = lookup_codename(release, 'n/a')
+        else:
+            release = rinfo.get('suite', 'unstable')
+            if release == 'testing':
+                # Would be nice if I didn't have to hardcode this.
+                codename = TESTING_CODENAME
+            else:
+                codename = 'sid'
+        distinfo.update({ 'RELEASE' : release, 'CODENAME' : codename })
+
+    if distinfo.get('RELEASE'):
+        distinfo['DESCRIPTION'] += ' %(RELEASE)s' % distinfo
+    if distinfo.get('CODENAME'):
+        distinfo['DESCRIPTION'] += ' (%(CODENAME)s)' % distinfo
+
+    return distinfo
+
+# Whatever is guessed above can be overridden in /etc/lsb-release
+def get_lsb_information():
+    distinfo = {}
+    if os.path.exists('/etc/lsb-release'):
+        for line in open('/etc/lsb-release'):
+            line = line.strip()
+            if not line:
+                continue
+            # Skip invalid lines
+            if not '=' in line:
+                continue
+            var, arg = line.split('=', 1)
+            if var.startswith('DISTRIB_'):
+                var = var[8:]
+                if arg.startswith('"') and arg.endswith('"'):
+                    arg = arg[1:-1]
+                distinfo[var] = arg
+    return distinfo
+
+def get_distro_information():
+    distinfo = guess_debian_release()
+    distinfo.update(get_lsb_information())
+    return distinfo
+
+def test():
+    print get_distro_information()
+    print check_modules_installed()
+
+if __name__ == '__main__':
+    test()