Index: Lib/platform.py =================================================================== --- Lib/platform.py (revision 58710) +++ Lib/platform.py (working copy) @@ -34,6 +34,7 @@ # # # +# 1.0.5 - fixed dist() unpredictable result # 1.0.3 - added normalization of Windows system name # 1.0.2 - added more Windows support # 1.0.1 - reformatted to make doc.py happy @@ -107,10 +108,18 @@ """ -__version__ = '1.0.4' +__version__ = '1.0.5' -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)' @@ -181,23 +190,24 @@ info = open('/var/adm/inst-log/info').readlines() distname = 'SuSE' for line in info: - tv = string.split(line) + tv = line.split() if len(tv) == 2: tag,value = tv else: continue if tag == 'MIN_DIST_VERSION': - version = string.strip(value) + version = value.strip() elif tag == 'DIST_IDENT': - values = string.split(value,'-') + 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() + info = open(installed).readlines() for line in info: - pkg = string.split(line,'-') + 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 ? @@ -217,58 +227,98 @@ return distname,version,id -_release_filename = re.compile(r'(\w+)[-_](release|version)') -_release_version = re.compile(r'([\d.]+)[^(]*(?:\((.+)\))?') # Note:In supported_dists below we need 'fedora' before 'redhat' as in # Fedora redhat-release is a link to fedora-release. -def dist(distname='',version='',id='', +def dist(distname='',version='',id=''): - supported_dists=('SuSE', 'debian', 'fedora', 'redhat', 'mandrake')): - """ 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 + _ETC_DIR and then reverts to _dist_try_harder() in case no suitable files are found. 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): + try: + file = open(lsb, 'r' ) + except IOError: + file = None + if file is not None: + for line in file.xreadlines(): + 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 + file.close() try: - etc = os.listdir('/etc') + etc = os.listdir(_ETC_DIR) except os.error: # Probably not a Unix system - return distname,version,id - for file in etc: - m = _release_filename.match(file) + 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: - _distname,dummy = m.groups() - if _distname in supported_dists: - distname = _distname - break - else: - return _dist_try_harder(distname,version,id) - f = open('/etc/'+file,'r') + 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 ] + if not found.has_key( 'distname' ): + found[ 'distname' ] = match.group( 1 ) + f = open( file, 'r' ) firstline = f.readline() f.close() m = _release_version.search(firstline) if m: - _version,_id = m.groups() + _distname,_version,_id,_descr = m.groups() + if _distname: + found[ 'distname' ] = _distname.replace( ' ', '' ) if _version: - version = _version + found[ 'version' ] = _version if _id: - id = _id + found[ 'id' ] = _id else: # Unkown format... take the first two words - l = string.split(string.strip(firstline)) + l = firstline.strip().split() if l: - version = l[0] + if not found.has_key( 'version' ): + found[ 'version' ] = l[0] if len(l) > 1: - id = l[1] - return distname,version,id + if not found.has_key( 'id' ): + found[ 'id' ] = l[1] + return ( found.get('distname',distname), + found.get( 'version', version ), + found.get( 'id', id ) ) class _popen: @@ -362,7 +412,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: @@ -371,7 +421,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.]+) ' @@ -416,7 +466,7 @@ return system,release,version # Parse the output - info = string.strip(info) + info = info.strip() m = _ver_output.match(info) if m: system,release,version = m.groups() @@ -674,7 +724,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]) @@ -683,7 +733,7 @@ else: major = major - 3 l[0] = str(major) - release = string.join(l,'.') + release = '.'.join(l) if release < '6': system = 'Solaris' else: @@ -713,29 +763,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 @@ -797,7 +837,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 @@ -819,7 +859,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 @@ -983,7 +1023,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 @@ -1027,12 +1067,6 @@ machine = '' if processor == 'unknown': processor = '' - - # normalize name - if system == 'Microsoft' and release == 'Windows': - system = 'Windows' - release = 'Vista' - _uname_cache = system,node,release,version,machine,processor return _uname_cache @@ -1122,10 +1156,10 @@ version, buildno, builddate, buildtime, compiler = \ _sys_version_parser.match(sys.version).groups() builddate = builddate + ' ' + buildtime - l = string.split(version, '.') + l = version.split('.') if len(l) == 2: l.append('0') - version = string.join(l, '.') + version = '.'.join(l) _sys_version_cache = (version, buildno, builddate, compiler) return _sys_version_cache @@ -1148,7 +1182,7 @@ will always include the patchlevel (it defaults to 0). """ - return string.split(_sys_version()[0], '.') + return _sys_version()[0].split('.') def python_build(): Index: Lib/test/platform/README.txt =================================================================== --- Lib/test/platform/README.txt (revision 0) +++ Lib/test/platform/README.txt (revision 0) @@ -0,0 +1,2 @@ +This directory contains *-release files for platform.dist() tests. + Property changes on: Lib/test/platform/README.txt ___________________________________________________________________ Name: svn:keywords + 'Id Revision' Name: svn:eol-style + native Index: Lib/test/platform/ubuntu_gutsy/debian_version =================================================================== --- Lib/test/platform/ubuntu_gutsy/debian_version (revision 0) +++ Lib/test/platform/ubuntu_gutsy/debian_version (revision 0) @@ -0,0 +1 @@ +lenny/sid Index: Lib/test/platform/ubuntu_gutsy/lsb-release =================================================================== --- Lib/test/platform/ubuntu_gutsy/lsb-release (revision 0) +++ Lib/test/platform/ubuntu_gutsy/lsb-release (revision 0) @@ -0,0 +1,4 @@ +DISTRIB_ID=Ubuntu +DISTRIB_RELEASE=7.10 +DISTRIB_CODENAME=gutsy +DISTRIB_DESCRIPTION="Ubuntu 7.10" Index: Lib/test/test_platform.py =================================================================== --- Lib/test/test_platform.py (revision 58710) +++ Lib/test/test_platform.py (working copy) @@ -1,3 +1,4 @@ +import os import unittest from test import test_support import platform @@ -2,2 +3,25 @@ +testdir = os.path.dirname(__file__) or os.curdir +platform_dir = os.path.join(testdir, "platform") + +dist_expected = { + 'ubuntu_gutsy' : ('Ubuntu', '7.10', 'gutsy'), + } + +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 +96,8 @@ def test_main(): test_support.run_unittest( - PlatformTest + PlatformTest, + PlatformDistTest ) if __name__ == '__main__':