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

lsb: Willingness to help for the Ubuntu merge



Hi Colin, hi Matthias,

now that the Ubuntu Pangolin was released (congrats!), from what I
understand from the Ubuntu release process, it will very soon be the
"big merge" time. And the src:lsb package has diverged quite a lot
between the Debian and Ubuntu counterparts.

Now, while I tried my best to merge the past and actual changes from
Ubuntu, there is certainly a diff that needs manual merging (hence
discussion). Furthermore, I don't think Ubuntu and Debian really need
different src:lsb packages (especially when we can play with dpkg-vendor
snippets where needed).

So I am willing to put work where needed towards the goal of sharing a
single Debian source package. Where do you want to start from?

(By the way, one major hurdle is probably the default python version for
lsb-release. The attached patch is an attempt at making the python
scripts work with both python2.6 and python3 without further change.
Comments welcome.)

Cheers,

OdyX
diff --git a/initdutils.py b/initdutils.py
index 3b5bb10..e911dfa 100644
--- a/initdutils.py
+++ b/initdutils.py
@@ -1,13 +1,10 @@
 # Support for scanning init scripts for LSB info
 
-import re, sys, os, cStringIO
-import cPickle
+# Python3-compatible print() function
+from __future__ import print_function
 
-try:
-    assert True
-except:
-    True = 1
-    False = 0
+import re, sys, os, io
+import pickle
 
 class RFC822Parser(dict):
     "A dictionary-like object."
@@ -15,14 +12,14 @@ class RFC822Parser(dict):
     
     def __init__(self, fileob=None, strob=None, startcol=0, basedict=None):
         if not fileob and not strob:
-            raise ValueError, 'need a file or string'
+            raise ValueError('need a file or string')
         if not basedict:
             basedict = {}
         
         super(RFC822Parser, self).__init__(basedict)
 
         if not fileob:
-            fileob = cStringIO.StringIO(strob)
+            fileob = io.StringIO(strob)
 
         key = None
         for line in fileob:
@@ -79,13 +76,13 @@ def scan_initfile(initfile):
 
     inheaders = RFC822Parser(strob=headerlines)
     headers = {}
-    for header, body in inheaders.iteritems():
+    for header, body in list(inheaders.items()):
         # Ignore empty headers
         if not body.strip():
             continue
         
         if header in ('Default-Start', 'Default-Stop'):
-            headers[header] = map(int, body.split())
+            headers[header] = list(map(int, body.split()))
         elif header in ('Required-Start', 'Required-Stop', 'Provides',
                         'Should-Start', 'Should-Stop'):
             headers[header] = body.split()
@@ -103,24 +100,24 @@ def save_facilities(facilities):
         return
     
     fh = file(FACILITIES, 'w')
-    for facility, entries in facilities.items():
+    for facility, entries in list(facilities.items()):
         # Ignore system facilities
         if facility.startswith('$'): continue
-        for (scriptname, pri) in entries.items():
+        for (scriptname, pri) in list(entries.items()):
             start, stop = pri
-            print >> fh, "%(scriptname)s %(facility)s %(start)d %(stop)d" % locals()
+            print("%(scriptname)s %(facility)s %(start)d %(stop)d" % locals(), file=fh)
     fh.close()
 
 def load_facilities():
     facilities = {}
     if os.path.exists(FACILITIES):
-        for line in open(FACILITIES).xreadlines():
+        for line in open(FACILITIES):
             try:
                 scriptname, name, start, stop = line.strip().split()
                 facilities.setdefault(name, {})[scriptname] = (int(start),
                                                                int(stop))
-            except ValueError, x:
-                print >> sys.stderr, 'Invalid facility line', line
+            except ValueError as x:
+                print('Invalid facility line', line, file=sys.stderr)
 
     return facilities
 
@@ -129,7 +126,7 @@ def load_depends():
 
     if os.path.exists(DEPENDS):
         independs = RFC822Parser(fileob=file(DEPENDS))
-        for initfile, facilities in independs.iteritems():
+        for initfile, facilities in list(independs.items()):
             depends[initfile] = facilities.split()
     return depends
 
@@ -142,8 +139,8 @@ def save_depends(depends):
         return
     
     fh = file(DEPENDS, 'w')
-    for initfile, facilities in depends.iteritems():
-        print >> fh, '%s: %s' % (initfile, ' '.join(facilities))
+    for initfile, facilities in list(depends.items()):
+        print('%s: %s' % (initfile, ' '.join(facilities)), file=fh)
     fh.close()
 
 # filemap entries are mappings, { (package, filename) : instloc }
@@ -152,7 +149,7 @@ def load_lsbinstall_info():
         return {}
     
     fh = open(LSBINSTALL, 'rb')
-    filemap = cPickle.load(fh)
+    filemap = pickle.load(fh)
     fh.close()
 
     # Just in case it's corrupted somehow
@@ -170,8 +167,8 @@ def save_lsbinstall_info(filemap):
         return
     
     fh = open(LSBINSTALL, 'wb')
-    cPickle.dump(fh, filemap)
+    pickle.dump(fh, filemap)
     fh.close()
 
 if __name__ == '__main__':
-    print scan_initfile('init-fragment')
+    print(scan_initfile('init-fragment'))
diff --git a/install_initd b/install_initd
index 4ec8452..3f3e86e 100755
--- a/install_initd
+++ b/install_initd
@@ -1,5 +1,8 @@
 #!/usr/bin/python
 
+# Python3-compatible print() function
+from __future__ import print_function
+
 import sys, re, os, initdutils
 
 if len(sys.argv) > 1:
@@ -12,7 +15,7 @@ if len(sys.argv) > 1:
     else:
         initfile = os.path.join('/etc/init.d', initfile)
 else:
-    print >> sys.stderr, 'Usage: %s /etc/init.d/<init-script>' % sys.argv[0]
+    print('Usage: %s /etc/init.d/<init-script>' % sys.argv[0], file=sys.stderr)
     sys.exit(1)
 
 # Default priorities
@@ -22,19 +25,19 @@ defstop = [0, 1, 6]
 
 # Estimated priorities of these facilities in Debian
 os_facilities = {
-    "$local_fs" : {'lsb' : (0, 100)},
-    "$network" : {'lsb' : (10, 50)},
-    "$remote_fs" : {'lsb': (19, 20)},
-    "$named" : {'lsb': (19, 19)},
-    "$syslog" : {'lsb' : (10, 89)},
+    "$local_fs": {'lsb' : (0, 100)},
+    "$network": {'lsb' : (10, 50)},
+    "$remote_fs": {'lsb': (19, 20)},
+    "$named": {'lsb': (19, 19)},
+    "$syslog": {'lsb' : (10, 89)},
     # No longer present in gLSB 1.2; however, required for gLSB 1.1
     # compat.  Note that these are looser than $portmap and $time;
     # anything specifying $netdaemons will be run later, which may not
     # be what you want...
-    "$netdaemons" : {'lsb': (80, 19)},
+    "$netdaemons": {'lsb': (80, 19)},
     # gLSB 1.2
-    "$portmap" : {'lsb' : (19, 34)},
-    "$time" : {'lsb' : (24, 21)},
+    "$portmap": {'lsb' : (19, 34)},
+    "$time": {'lsb' : (24, 21)},
     }
 
 facilities = initdutils.load_facilities()
@@ -51,10 +54,10 @@ if reqstart or shouldstart:
     startpri = 5
     for facility in reqstart:
         if facility not in facilities:
-            print >> sys.stderr, 'Missing required start facility', facility
+            print('Missing required start facility', facility, file=sys.stderr)
             sys.exit(1)
         else:
-            for script, pri in facilities[facility].iteritems():
+            for script, pri in list(facilities[facility].items()):
                 if script != initfile:
                     start, stop = pri
                     startpri = max(startpri, start+1)
@@ -63,9 +66,9 @@ if reqstart or shouldstart:
     
     for facility in shouldstart:
         if facility not in facilities:
-            print >> sys.stderr, 'Missing should-start facility', facility, '(ignored)'
+            print('Missing should-start facility', facility, '(ignored)', file=sys.stderr)
         else:
-            for script, pri in facilities[facility].iteritems():
+            for script, pri in list(facilities[facility].items()):
                 if script != initfile:
                     start, stop = pri
                     startpri = max(startpri, start+1)
@@ -77,10 +80,10 @@ if reqstop or shouldstop:
     stoppri = 95
     for facility in reqstop:
         if facility not in facilities:
-            print >> sys.stderr, 'Missing required stop facility', facility
+            print('Missing required stop facility', facility, file=sys.stderr)
             sys.exit(1)
         else:
-            for script, pri in facilities[facility].iteritems():
+            for script, pri in list(facilities[facility].items()):
                 if script != initfile:
                     start, stop = pri
                     stoppri = min(stoppri, stop-1)
@@ -89,9 +92,9 @@ if reqstop or shouldstop:
 
     for facility in shouldstop:
         if facility not in facilities:
-            print >> sys.stderr, 'Missing should-stop facility', facility, '(ignored)'
+            print('Missing should-stop facility', facility, '(ignored)', file=sys.stderr)
         else:
-            for script, pri in facilities[facility].iteritems():
+            for script, pri in list(facilities[facility].items()):
                 if script != initfile:
                     start, stop = pri
                     stoppri = min(stoppri, stop-1)
@@ -105,9 +108,9 @@ provides = headers.get('Provides', [])
 if provides:
     for facility in provides:
         if facility[0] == '$':
-            print >> sys.stderr, 'Ignoring system-provided facility', facility
+            print('Ignoring system-provided facility', facility, file=sys.stderr)
             continue
-        if not facilities.has_key(facility):
+        if facility not in facilities:
             facilities[facility] = {}
 
         facilities[facility][initfile] = (startpri, stoppri)
@@ -117,13 +120,13 @@ defstart = headers.get('Default-Start', defstart)
 defstop = headers.get('Default-Stop', defstop)
 
 # A set type would be nice... [range(2,6) = 2..5]
-for level in range(2,6):
+for level in range(2, 6):
     if level in defstart:
-        for i in range(2,6):
+        for i in range(2, 6):
             if i not in defstart:
                 defstart.append(i)
     if level in defstop:
-        for i in range(2,6):
+        for i in range(2, 6):
             if i not in defstop:
                 defstop.append(i)
 
diff --git a/lsb_release b/lsb_release
index f8e8a53..abb201f 100755
--- a/lsb_release
+++ b/lsb_release
@@ -17,9 +17,11 @@
 #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 #    02110-1301 USA
 
+# Python3-compatible print() function
+from __future__ import print_function
+
 from optparse import OptionParser
 import sys
-import commands
 import os
 import re
 
@@ -62,35 +64,35 @@ def main():
     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."
+            print("No LSB modules are available.", file=sys.stderr)
         elif short:
-            print ':'.join(verinfo)
+            print(':'.join(verinfo))
         else:
-            print 'LSB Version:\t' + ':'.join(verinfo)
+            print('LSB Version:\t' + ':'.join(verinfo))
 
     if options.id or options.all:
         if short:
-            print distinfo.get('ID', 'n/a')
+            print(distinfo.get('ID', 'n/a'))
         else:
-            print 'Distributor ID:\t%s' % distinfo.get('ID', 'n/a')
+            print('Distributor ID:\t%s' % distinfo.get('ID', 'n/a'))
 
     if options.description or options.all:
         if short:
-            print distinfo.get('DESCRIPTION', 'n/a')
+            print(distinfo.get('DESCRIPTION', 'n/a'))
         else:
-            print 'Description:\t%s' % distinfo.get('DESCRIPTION', 'n/a')
+            print('Description:\t%s' % distinfo.get('DESCRIPTION', 'n/a'))
 
     if options.release or options.all:
         if short:
-            print distinfo.get('RELEASE', 'n/a')
+            print(distinfo.get('RELEASE', 'n/a'))
         else:
-            print 'Release:\t%s' % distinfo.get('RELEASE', 'n/a')
+            print('Release:\t%s' % distinfo.get('RELEASE', 'n/a'))
 
     if options.codename or options.all:
         if short:
-            print distinfo.get('CODENAME', 'n/a')
+            print(distinfo.get('CODENAME', 'n/a'))
         else:
-            print 'Codename:\t%s' % distinfo.get('CODENAME', 'n/a')
+            print('Codename:\t%s' % distinfo.get('CODENAME', 'n/a'))
 
 if __name__ == '__main__':
     main()
diff --git a/lsb_release.py b/lsb_release.py
index 2727d13..33c189c 100644
--- a/lsb_release.py
+++ b/lsb_release.py
@@ -17,8 +17,11 @@
 #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 #    02110-1301 USA
 
+# Python3-compatible print() function
+from __future__ import print_function
+
 import sys
-import commands
+import subprocess
 import os
 import re
 
@@ -42,9 +45,9 @@ RELEASE_CODENAME_LOOKUP = {
 
 TESTING_CODENAME = 'unknown.new.testing'
 
-RELEASES_ORDER = RELEASE_CODENAME_LOOKUP.items()
+RELEASES_ORDER = list(RELEASE_CODENAME_LOOKUP.items())
 RELEASES_ORDER.sort()
-RELEASES_ORDER = list(zip(*RELEASES_ORDER)[1])
+RELEASES_ORDER = list(list(zip(*RELEASES_ORDER))[1])
 RELEASES_ORDER.extend(['stable', 'testing', 'unstable', 'sid'])
 
 def lookup_codename(release, unknown=None):
@@ -120,7 +123,11 @@ except NameError:
 # 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)
+    output = subprocess.Popen(['dpkg-query','-f',"'${Version} ${Provides}\n'",'-W',PACKAGES],
+                              env={'LANG': 'C'},
+                              stdout=subprocess.PIPE,
+                              stderr=subprocess.PIPE,
+                              close_fds=True).communicate()[0].decode('ascii')
     if not output:
         return []
 
@@ -164,22 +171,21 @@ def parse_policy_line(data):
                 retval[longnames[k]] = v
     return retval
 
-def compare_release(x, y):
+def release_index(x):
     suite_x = x[1].get('suite')
-    suite_y = y[1].get('suite')
 
-    if suite_x and suite_y:
-        if suite_x in RELEASES_ORDER and suite_y in RELEASES_ORDER:
-            return RELEASES_ORDER.index(suite_y)-RELEASES_ORDER.index(suite_x)
-        else:
-            return cmp(suite_x, suite_y)
+    if suite_x in RELEASES_ORDER:
+        return RELEASES_ORDER.index(suite_x)
 
     return 0
 
 def parse_apt_policy():
     data = []
     
-    policy = commands.getoutput('LANG=C apt-cache policy 2>/dev/null')
+    policy = subprocess.Popen(['apt-cache','policy'],
+                              env={'LANG': 'C'},
+                              stdout=subprocess.PIPE,
+                              close_fds=True).communicate()[0].decode('ascii')
     for line in policy.split('\n'):
         line = line.strip()
         m = re.match(r'(-?\d+)', line)
@@ -213,15 +219,14 @@ def guess_release_from_apt(origin='Debian', component='main',
     if not releases:
         return None
     
-    releases.sort()
-    releases.reverse()
+    releases.sort(key=lambda tuple: tuple[0],reverse=True)
 
     # We've sorted the list by descending priority, so the first entry should
     # be the "main" release in use on the system
 
     max_priority = releases[0][0]
     releases = [x for x in releases if x[0] == max_priority]
-    releases.sort(compare_release)
+    releases.sort(key=release_index)
 
     return releases[0][1]
 
@@ -244,8 +249,8 @@ def guess_debian_release():
         try:
             with open('/etc/debian_version') as debian_version:
                 release = debian_version.read().strip()
-        except IOError, msg:
-            print >> sys.stderr, 'Unable to open /etc/debian_version:', str(msg)
+        except IOError as msg:
+            print('Unable to open /etc/debian_version:', str(msg), file=sys.stderr)
             release = 'unknown'
             
         if not release[0:1].isalpha():
@@ -315,8 +320,8 @@ def get_lsb_information():
                             arg = arg[1:-1]
                         if arg: # Ignore empty arguments
                             distinfo[var] = arg.strip()
-        except IOError, msg:
-            print >> sys.stderr, 'Unable to open /etc/lsb-release:', str(msg)
+        except IOError as msg:
+            print('Unable to open /etc/lsb-release:', str(msg), file=sys.stderr)
             
     return distinfo
 
@@ -332,8 +337,8 @@ def get_distro_information():
         return lsbinfo
 
 def test():
-    print get_distro_information()
-    print check_modules_installed()
+    print(get_distro_information())
+    print(check_modules_installed())
 
 if __name__ == '__main__':
     test()
diff --git a/lsbinstall b/lsbinstall
index f007517..30ad303 100755
--- a/lsbinstall
+++ b/lsbinstall
@@ -1,10 +1,13 @@
 #!/usr/bin/python
 
+# Python3-compatible print() function
+from __future__ import print_function
+
 import sys
 import os
 import shutil
 import socket
-import commands
+import subprocess
 from tempfile import NamedTemporaryFile
 from initdutils import load_lsbinstall_info, save_lsbinstall_info
 
@@ -19,7 +22,7 @@ objecttypes = (
     )
 
 def installed_message(objectname):
-    print objectname, 'is installed'
+    print(objectname, 'is installed')
 
 def handle_generic_install(options, args, location, showinstloc=False):
     filename = args[0]
@@ -40,9 +43,9 @@ def handle_generic_install(options, args, location, showinstloc=False):
         if os.path.exists(fileinfo):
             try:
                 os.unlink(fileinfo)
-            except (IOError, OSError, os.error), why:
-                print >> sys.stderr, 'Removal of %s failed: %s' % (
-                    instloc, str(why))
+            except (IOError, OSError, os.error) as why:
+                print('Removal of %s failed: %s' % (
+                    instloc, str(why)), file=sys.stderr)
                 sys.exit(1)
 
         # Remove it from the database, even if it was previously removed
@@ -54,27 +57,27 @@ def handle_generic_install(options, args, location, showinstloc=False):
         instloc = os.path.join(location, '%s.%s' % (options.package, basename))
 
     if os.path.exists(instloc):
-        print >> sys.stderr, 'Unable to install %s: %s exists' % (
-            filename, instloc)
+        print('Unable to install %s: %s exists' % (
+            filename, instloc), file=sys.stderr)
         sys.exit(1)
 
     if not os.path.exists(location):
         try:
             os.makedirs(location)
-        except (IOError, OSError, os.error), why:
-            print >> sys.stderr, 'Unable to create %s to install %s: %s' % (
-                location, filename, str(why))
+        except (IOError, OSError, os.error) as why:
+            print('Unable to create %s to install %s: %s' % (
+                location, filename, str(why)), file=sys.stderr)
             sys.exit(1)
         
     try:
         shutil.copy2(filename, instloc)
-    except (IOError, os.error), why:
-        print >> sys.stderr, 'Installation of %s as %s failed: %s' % (
-            filename, instloc, str(why))
+    except (IOError, os.error) as why:
+        print('Installation of %s as %s failed: %s' % (
+            filename, instloc, str(why)), file=sys.stderr)
         sys.exit(1)
         
     if showinstloc:
-        print instloc
+        print(instloc)
 
     filemap[(package, filename)] = instloc
     save_lsbinstall_info(filemap)
@@ -91,7 +94,7 @@ def handle_service(options, args):
         port, proto = pproto.split('/', 1)
         port = int(port)
     except:
-        print >> sys.stderr, 'You must specify a port/protocol pair as the first argument.'
+        print('You must specify a port/protocol pair as the first argument.', file=sys.stderr)
         sys.exit(2)
 
     if options.check:
@@ -100,7 +103,7 @@ def handle_service(options, args):
         except socket.error:
             sys.exit(1)
 
-        print '%d/%s corresponds to service %s' % (port, proto, serv)
+        print('%d/%s corresponds to service %s' % (port, proto, serv))
         return
 
     sname = args[1]
@@ -143,7 +146,7 @@ def handle_service(options, args):
                             laliases += [a]
                 elif name == lname or name in laliases:
                     # name shows up, but in wrong protocol/port
-                    print >> sys.stderr, 'Conflict between specified addition and /etc/services; aborting.'
+                    print('Conflict between specified addition and /etc/services; aborting.', file=sys.stderr)
                     fpout.close()
                     os.unlink(newfname)
                     sys.exit(1)
@@ -157,7 +160,7 @@ def handle_service(options, args):
                 line = '%15s %15s %s' % lname, lpproto, endbits
                 line = line.rstrip()
 
-            print >> fpout, line
+            print(line, file=fpout)
         
         fpin.close()
         fpout.close()
@@ -167,12 +170,12 @@ def handle_service(options, args):
         return
 
     fp = open('/etc/services', 'a')
-    print >> fp, '%15s %15s %s # Added by lsbinstall for %s' % (
-        sname, pproto, ' '.join(saliases), pkg)
+    print('%15s %15s %s # Added by lsbinstall for %s' % (
+        sname, pproto, ' '.join(saliases), pkg), file=fp)
     fp.close()
 
 def handle_inet(options, args, parser):
-    cmd = 'update-inetd --group LSB '
+    cmd = ['update-inetd','--group','LSB']
 
     alist = list(args[0].split(':'))
     if len(alist) < 2:
@@ -184,7 +187,7 @@ def handle_inet(options, args, parser):
     
     if options.remove:
         parts = r'%s\s+.*\s+%s\s+.*' % (re.escape(alist[0], alist[1]))
-        cmd += '--remove '+commands.mkarg(parts)
+        cmd.extend(['--remove',parts])
     elif options.check:
         return
     else:
@@ -192,9 +195,9 @@ def handle_inet(options, args, parser):
             parser.error('The operand must have six colon-separated arguments.')
             return
         newalist = [alist[0], alist[2], alist[1]] + alist[3:]
-        cmd += '--add '+commands.mkarg('\t'.join(newalist))
+        cmd.extend(['--add','\t'.join(newalist)])
 
-    os.system(cmd)
+    subprocess.call(cmd)
     pass
 
 def handle_man(options, args):
@@ -264,7 +267,7 @@ def main():
             parser.error('Only one argument supported for %s' % options.type)
         handle_man(options, args)
     else:
-        print >> sys.stderr, 'Unsupported type %s' % options.type
+        print('Unsupported type %s' % options.type, file=sys.stderr)
         sys.exit(1)
 
 if __name__ == '__main__':
diff --git a/remove_initd b/remove_initd
index 0322c7f..29e3dce 100755
--- a/remove_initd
+++ b/remove_initd
@@ -1,5 +1,8 @@
 #!/usr/bin/python
 
+# Python3-compatible print() function
+from __future__ import print_function
+
 import sys, re, os, initdutils
 
 if len(sys.argv) > 1:
@@ -12,7 +15,7 @@ if len(sys.argv) > 1:
     else:
         initfile = os.path.join('/etc/init.d', initfile)
 else:
-    print >> sys.stderr, 'Usage: %s /etc/init.d/<init-script>' % sys.argv[0]
+    print('Usage: %s /etc/init.d/<init-script>' % sys.argv[0], file=sys.stderr)
     sys.exit(1)
 
 headers = initdutils.scan_initfile(initfile)
@@ -25,18 +28,18 @@ if provides:
     for facility in provides:
         if facility in facilities:
             entries = {}
-            for entry in facilities[facility].items():
+            for entry in list(facilities[facility].items()):
                 if entry[0] != initfile:
                     entries[entry[0]] = entry[1]
             facilities[facility] = entries
 
-    for (initscript, needed) in depends.iteritems():
+    for (initscript, needed) in list(depends.items()):
         for facility in needed:
             if facility[0] == "$":
                 continue
             if not facilities.get(facility) and facility in provides:
-                print >> sys.stderr, 'Unable to remove %s: %s needs %s\n' % (
-                    initfile, initscript, facility)
+                print('Unable to remove %s: %s needs %s\n' % (
+                    initfile, initscript, facility), file=sys.stderr)
                 sys.exit(1)
 
     if initfile in depends:

Attachment: signature.asc
Description: OpenPGP digital signature


Reply to: