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