Index: Misc/NEWS =================================================================== --- Misc/NEWS (revisão 62996) +++ Misc/NEWS (cópia de trabalho) @@ -897,6 +897,8 @@ - #1492: The content type of BaseHTTPServer error messages can now be overridden. +- Issue #1322: platform.dist() has unpredictable result under Linux + - Issue 1781: ConfigParser now does not let you add the "default" section (ignore-case) Index: Lib/platform.py =================================================================== --- Lib/platform.py (revisão 62996) +++ Lib/platform.py (cópia de trabalho) @@ -34,6 +34,7 @@ # # # +# 1.0.7 - fixed dist() unpredictable result # 1.0.6 - added linux_distribution() # 1.0.5 - fixed Java support to allow running the module on Jython # 1.0.4 - added IronPython support @@ -110,10 +111,17 @@ """ -__version__ = '1.0.6' +__version__ = '1.0.7' -import sys,string,os,re +import sys +import os +import re +_release_filename = re.compile( r'(\w+)[-_](release|version)' ) +_release_version = re.compile( r'(.*)\s+release\s+(.*)\s+\((.*)\)\s+(.*)' ) +_lsb_variable = re.compile( r'(\w+)=(.*)' ) +_ETC_DIR = '/etc' + ### Platform specific APIs _libc_search = re.compile(r'(__libc_init)' @@ -186,30 +194,31 @@ """ if os.path.exists('/var/adm/inst-log/info'): # SuSE Linux stores distribution information in that file - info = open('/var/adm/inst-log/info').readlines() - distname = 'SuSE' - for line in info: - tv = string.split(line) - if len(tv) == 2: - tag,value = tv - else: - continue - if tag == 'MIN_DIST_VERSION': - version = string.strip(value) - elif tag == 'DIST_IDENT': - values = string.split(value,'-') - id = values[2] - return distname,version,id + with open('/var/adm/inst-log/info') as fp: + distname = 'SuSE' + for line in fp: + tv = line.split() + if len(tv) == 2: + tag,value = tv + else: + continue + if tag == 'MIN_DIST_VERSION': + version = value.strip() + elif tag == 'DIST_IDENT': + values = value.split('-') + id = values[2] + return distname,version,id - if os.path.exists('/etc/.installed'): + installed = os.path.join(_ETC_DIR, '.installed') + if os.path.exists(installed): # Caldera OpenLinux has some infos in that file (thanks to Colin Kong) - info = open('/etc/.installed').readlines() - for line in info: - pkg = string.split(line,'-') - if len(pkg) >= 2 and pkg[0] == 'OpenLinux': - # XXX does Caldera support non Intel platforms ? If yes, - # where can we find the needed id ? - return 'OpenLinux',pkg[1],id + with open(installed) as fp: + for line in fp: + pkg = line.split('-') + if len(pkg) >= 2 and pkg[0] == 'OpenLinux': + # XXX does Caldera support non Intel platforms ? If yes, + # where can we find the needed id ? + return 'OpenLinux',pkg[1],id if os.path.isdir('/usr/lib/setup'): # Check for slackware verson tag file (thanks to Greg Andruk) @@ -259,7 +268,7 @@ return tuple(m.groups()) # Unkown format... take the first two words - l = string.split(string.strip(firstline)) + l = firstline.strip().split() if l: version = l[0] if len(l) > 1: @@ -286,66 +295,88 @@ if parsed != output: print (input, parsed) -def linux_distribution(distname='', version='', id='', +def linux_distribution(distname='', version='', id=''): - supported_dists=_supported_dists, - full_distribution_name=1): - """ Tries to determine the name of the Linux OS distribution name. The function first looks for a distribution release file in /etc and then reverts to _dist_try_harder() in case no suitable files are found. - supported_dists may be given to define the set of Linux - distributions to look for. It defaults to a list of currently - supported Linux distributions identified by their release file - name. - - If full_distribution_name is true (default), the full - distribution read from the OS is returned. Otherwise the short - name taken from supported_dists is used. - Returns a tuple (distname,version,id) which default to the args given as parameters. """ + + # found will contains elements that have been set from _ETC_DIR files parsing + found = {} + # First read _ETC_DIR/lsb-release to initialize distname, version and id + lsb = os.path.join(_ETC_DIR, "lsb-release") + if os.path.exists(lsb): + with open(lsb, 'r') as fp: + for line in fp: + m = _lsb_variable.match( line ) + if m: + n, v = m.groups() + if v: + if n=='DISTRIB_ID': found[ 'distname' ] = v + elif n == 'DISTRIB_RELEASE': found[ 'version' ] = v + elif n == 'DISTRIB_CODENAME': found[ 'id' ] = v + try: - etc = os.listdir('/etc') + etc = os.listdir(_ETC_DIR) except os.error: # Probably not a Unix system - return distname,version,id - etc.sort() - for file in etc: - m = _release_filename.match(file) - if m is not None: - _distname,dummy = m.groups() - if _distname in supported_dists: - distname = _distname - break - else: - return _dist_try_harder(distname,version,id) + return ( found.get('distname', distname), + found.get( 'version', version ), + found.get( 'id', id ) ) + # Look for other release files in _ETC_DIR + filesAndMatch = [] + for f in etc: + file = os.path.join(_ETC_DIR, f) + if file == lsb or os.path.islink(file) or not os.path.isfile(file): + continue + m = _release_filename.match(f) + if m: + filesAndMatch.append( ( file, m ) ) + + if not filesAndMatch: + # No release file found + return _dist_try_harder( found.get('distname',distname), + found.get( 'version', version ), + found.get( 'id', id ) ) + + if len( filesAndMatch ) > 1: + # If there are several _ETC_DIR/*-release or _ETC_DIR/*-version files + # they are sorted so that the result is always the same whatever + # the order returned by os.listdir(_ETC_DIR) + filesAndMatch.sort() + + file, match = filesAndMatch[ 0 ] + + with open( file, 'r' ) as fp: + firstline = fp.readline() + + _distname, _version, _id = _parse_release_file(firstline) + + if _distname: + if not found.has_key( 'distname' ): + found[ 'distname' ] = _distname.replace ( ' ', '' ) + if _version: + if not found.has_key( 'version' ): + found[ 'version' ] = _version + if _id: + if not found.has_key( 'id' ): + found[ 'id' ] = _id - # Read the first line - f = open('/etc/'+file, 'r') - firstline = f.readline() - f.close() - _distname, _version, _id = _parse_release_file(firstline) + return ( found.get('distname',distname), + found.get( 'version', version ), + found.get( 'id', id ) ) - if _distname and full_distribution_name: - distname = _distname - if _version: - version = _version - if _id: - id = _id - return distname, version, id - # To maintain backwards compatibility: -def dist(distname='',version='',id='', +def dist(distname='',version='',id=''): - supported_dists=_supported_dists): - """ Tries to determine the name of the Linux OS distribution name. The function first looks for a distribution release file in @@ -356,9 +387,7 @@ args given as parameters. """ - return linux_distribution(distname, version, id, - supported_dists=supported_dists, - full_distribution_name=0) + return linux_distribution(distname, version, id) class _popen: @@ -452,7 +481,7 @@ """ Normalize the version and build strings and return a single version string using the format major.minor.build (or patchlevel). """ - l = string.split(version,'.') + l = version.split('.') if build: l.append(build) try: @@ -461,7 +490,7 @@ strings = l else: strings = map(str,ints) - version = string.join(strings[:3],'.') + version = '.'.join(strings[:3]) return version _ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) ' @@ -506,7 +535,7 @@ return system,release,version # Parse the output - info = string.strip(info) + info = info.strip() m = _ver_output.match(info) if m is not None: system,release,version = m.groups() @@ -818,7 +847,7 @@ # These releases use the old name SunOS return system,release,version # Modify release (marketing release = SunOS release - 3) - l = string.split(release,'.') + l = release.split('.') if l: try: major = int(l[0]) @@ -827,7 +856,7 @@ else: major = major - 3 l[0] = str(major) - release = string.join(l,'.') + release = '.'.join(l) if release < '6': system = 'Solaris' else: @@ -857,29 +886,19 @@ """ Helper to format the platform string in a filename compatible format e.g. "system-version-machine". """ - # Format the platform string - platform = string.join( - map(string.strip, - filter(len, args)), - '-') + platform = '-'.join(s.strip() for s in args) # Cleanup some possible filename obstacles... - replace = string.replace - platform = replace(platform,' ','_') - platform = replace(platform,'/','-') - platform = replace(platform,'\\','-') - platform = replace(platform,':','-') - platform = replace(platform,';','-') - platform = replace(platform,'"','-') - platform = replace(platform,'(','-') - platform = replace(platform,')','-') + platform = platform.replace(' ', '_') + for s in ('/', '\\', ':', ';', '"', "'", '(', ')'): + platform = platform.replace(s, '-') # No need to report 'unknown' information... - platform = replace(platform,'unknown','') + platform = platform.replace('unknown', '') # Fold '--'s and remove trailing '-' while 1: - cleaned = replace(platform,'--','-') + cleaned = platform.replace('--', '-') if cleaned == platform: break platform = cleaned @@ -941,7 +960,7 @@ f = os.popen('uname %s 2> /dev/null' % option) except (AttributeError,os.error): return default - output = string.strip(f.read()) + output = f.read().strip() rc = f.close() if not output or rc: return default @@ -963,7 +982,7 @@ f = os.popen('file %s 2> /dev/null' % target) except (AttributeError,os.error): return default - output = string.strip(f.read()) + output = f.read().strip() rc = f.close() if not output or rc: return default @@ -1146,7 +1165,7 @@ elif system[:4] == 'java': release,vendor,vminfo,osinfo = java_ver() system = 'Java' - version = string.join(vminfo,', ') + version = ', '.join(vminfo) if not version: version = vendor @@ -1191,7 +1210,7 @@ if processor == 'unknown': processor = '' - # normalize name + # normalize name if system == 'Microsoft' and release == 'Windows': system = 'Windows' release = 'Vista' @@ -1355,10 +1374,10 @@ builddate = builddate + ' ' + buildtime # Add the patchlevel version if missing - l = string.split(version, '.') + l = version.split('.') if len(l) == 2: l.append('0') - version = string.join(l, '.') + version = '.'.join(l) # Build and cache the result result = (name, version, branch, revision, buildno, builddate, compiler) @@ -1415,7 +1434,7 @@ """ if hasattr(sys, 'version_info'): return sys.version_info[:3] - return tuple(string.split(_sys_version()[1], '.')) + return tuple(_sys_version()[1].split('.')) def python_branch(): Index: Lib/test/test_platform.py =================================================================== --- Lib/test/test_platform.py (revisão 62996) +++ Lib/test/test_platform.py (cópia de trabalho) @@ -1,3 +1,4 @@ +import os import unittest from test import test_support import platform @@ -2,2 +3,27 @@ +testdir = os.path.dirname(__file__) or os.curdir +platform_dir = os.path.join(testdir, "platform") + +dist_expected = { + 'ubuntu_gutsy' : ('Ubuntu', '7.10', 'gutsy'), + 'redhat_nahant' : ('redhat', '4', 'Nahant'), + 'debian_etch' : ('debian', '4.0', ''), + 'centos_release5' : ('redhat', '5', 'Final'), + } + +class PlatformDistTest(unittest.TestCase): + + def setUp(self): + self.etc = platform._ETC_DIR + + def tearDown(self): + platform._ETC_DIR = self.etc + + def test_dist(self): + for subdir, expected in dist_expected.items(): + directory = os.path.join(platform_dir, subdir) + platform._ETC_DIR = directory + result = platform.dist() + self.assertEqual(result, expected) + class PlatformTest(unittest.TestCase): @@ -72,7 +98,8 @@ def test_main(): test_support.run_unittest( - PlatformTest + PlatformTest, + PlatformDistTest ) if __name__ == '__main__':