OILS / opy / _regtest / src / platform.py View on Github | oilshell.org

1620 lines, 814 significant
1#!/usr/bin/env python
2
3""" This module tries to retrieve as much platform-identifying data as
4 possible. It makes this information available via function APIs.
5
6 If called from the command line, it prints the platform
7 information concatenated as single string to stdout. The output
8 format is useable as part of a filename.
9
10"""
11# This module is maintained by Marc-Andre Lemburg <mal@egenix.com>.
12# If you find problems, please submit bug reports/patches via the
13# Python bug tracker (http://bugs.python.org) and assign them to "lemburg".
14#
15# Note: Please keep this module compatible to Python 1.5.2.
16#
17# Still needed:
18# * more support for WinCE
19# * support for MS-DOS (PythonDX ?)
20# * support for Amiga and other still unsupported platforms running Python
21# * support for additional Linux distributions
22#
23# Many thanks to all those who helped adding platform-specific
24# checks (in no particular order):
25#
26# Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell,
27# Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef
28# Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
29# Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
30# Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
31# Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter, Steve
32# Dower
33#
34# History:
35#
36# <see CVS and SVN checkin messages for history>
37#
38# 1.0.8 - changed Windows support to read version from kernel32.dll
39# 1.0.7 - added DEV_NULL
40# 1.0.6 - added linux_distribution()
41# 1.0.5 - fixed Java support to allow running the module on Jython
42# 1.0.4 - added IronPython support
43# 1.0.3 - added normalization of Windows system name
44# 1.0.2 - added more Windows support
45# 1.0.1 - reformatted to make doc.py happy
46# 1.0.0 - reformatted a bit and checked into Python CVS
47# 0.8.0 - added sys.version parser and various new access
48# APIs (python_version(), python_compiler(), etc.)
49# 0.7.2 - fixed architecture() to use sizeof(pointer) where available
50# 0.7.1 - added support for Caldera OpenLinux
51# 0.7.0 - some fixes for WinCE; untabified the source file
52# 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
53# vms_lib.getsyi() configured
54# 0.6.1 - added code to prevent 'uname -p' on platforms which are
55# known not to support it
56# 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
57# did some cleanup of the interfaces - some APIs have changed
58# 0.5.5 - fixed another type in the MacOS code... should have
59# used more coffee today ;-)
60# 0.5.4 - fixed a few typos in the MacOS code
61# 0.5.3 - added experimental MacOS support; added better popen()
62# workarounds in _syscmd_ver() -- still not 100% elegant
63# though
64# 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
65# return values (the system uname command tends to return
66# 'unknown' instead of just leaving the field empty)
67# 0.5.1 - included code for slackware dist; added exception handlers
68# to cover up situations where platforms don't have os.popen
69# (e.g. Mac) or fail on socket.gethostname(); fixed libc
70# detection RE
71# 0.5.0 - changed the API names referring to system commands to *syscmd*;
72# added java_ver(); made syscmd_ver() a private
73# API (was system_ver() in previous versions) -- use uname()
74# instead; extended the win32_ver() to also return processor
75# type information
76# 0.4.0 - added win32_ver() and modified the platform() output for WinXX
77# 0.3.4 - fixed a bug in _follow_symlinks()
78# 0.3.3 - fixed popen() and "file" command invocation bugs
79# 0.3.2 - added architecture() API and support for it in platform()
80# 0.3.1 - fixed syscmd_ver() RE to support Windows NT
81# 0.3.0 - added system alias support
82# 0.2.3 - removed 'wince' again... oh well.
83# 0.2.2 - added 'wince' to syscmd_ver() supported platforms
84# 0.2.1 - added cache logic and changed the platform string format
85# 0.2.0 - changed the API to use functions instead of module globals
86# since some action take too long to be run on module import
87# 0.1.0 - first release
88#
89# You can always get the latest version of this module at:
90#
91# http://www.egenix.com/files/python/platform.py
92#
93# If that URL should fail, try contacting the author.
94
95__copyright__ = """
96 Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
97 Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:info@egenix.com
98
99 Permission to use, copy, modify, and distribute this software and its
100 documentation for any purpose and without fee or royalty is hereby granted,
101 provided that the above copyright notice appear in all copies and that
102 both that copyright notice and this permission notice appear in
103 supporting documentation or portions thereof, including modifications,
104 that you make.
105
106 EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
107 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
108 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
109 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
110 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
111 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
112 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
113
114"""
115
116__version__ = '1.0.7'
117
118import sys,string,os,re
119
120### Globals & Constants
121
122# Determine the platform's /dev/null device
123try:
124 DEV_NULL = os.devnull
125except AttributeError:
126 # os.devnull was added in Python 2.4, so emulate it for earlier
127 # Python versions
128 if sys.platform in ('dos','win32','win16','os2'):
129 # Use the old CP/M NUL as device name
130 DEV_NULL = 'NUL'
131 else:
132 # Standard Unix uses /dev/null
133 DEV_NULL = '/dev/null'
134
135### Platform specific APIs
136
137_libc_search = re.compile(r'(__libc_init)'
138 '|'
139 '(GLIBC_([0-9.]+))'
140 '|'
141 '(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)')
142
143def libc_ver(executable=sys.executable,lib='',version='',
144
145 chunksize=2048):
146
147 """ Tries to determine the libc version that the file executable
148 (which defaults to the Python interpreter) is linked against.
149
150 Returns a tuple of strings (lib,version) which default to the
151 given parameters in case the lookup fails.
152
153 Note that the function has intimate knowledge of how different
154 libc versions add symbols to the executable and thus is probably
155 only useable for executables compiled using gcc.
156
157 The file is read and scanned in chunks of chunksize bytes.
158
159 """
160 if hasattr(os.path, 'realpath'):
161 # Python 2.2 introduced os.path.realpath(); it is used
162 # here to work around problems with Cygwin not being
163 # able to open symlinks for reading
164 executable = os.path.realpath(executable)
165 f = open(executable,'rb')
166 binary = f.read(chunksize)
167 pos = 0
168 while 1:
169 m = _libc_search.search(binary,pos)
170 if not m:
171 binary = f.read(chunksize)
172 if not binary:
173 break
174 pos = 0
175 continue
176 libcinit,glibc,glibcversion,so,threads,soversion = m.groups()
177 if libcinit and not lib:
178 lib = 'libc'
179 elif glibc:
180 if lib != 'glibc':
181 lib = 'glibc'
182 version = glibcversion
183 elif glibcversion > version:
184 version = glibcversion
185 elif so:
186 if lib != 'glibc':
187 lib = 'libc'
188 if soversion and soversion > version:
189 version = soversion
190 if threads and version[-len(threads):] != threads:
191 version = version + threads
192 pos = m.end()
193 f.close()
194 return lib,version
195
196def _dist_try_harder(distname,version,id):
197
198 """ Tries some special tricks to get the distribution
199 information in case the default method fails.
200
201 Currently supports older SuSE Linux, Caldera OpenLinux and
202 Slackware Linux distributions.
203
204 """
205 if os.path.exists('/var/adm/inst-log/info'):
206 # SuSE Linux stores distribution information in that file
207 info = open('/var/adm/inst-log/info').readlines()
208 distname = 'SuSE'
209 for line in info:
210 tv = string.split(line)
211 if len(tv) == 2:
212 tag,value = tv
213 else:
214 continue
215 if tag == 'MIN_DIST_VERSION':
216 version = string.strip(value)
217 elif tag == 'DIST_IDENT':
218 values = string.split(value,'-')
219 id = values[2]
220 return distname,version,id
221
222 if os.path.exists('/etc/.installed'):
223 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
224 info = open('/etc/.installed').readlines()
225 for line in info:
226 pkg = string.split(line,'-')
227 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
228 # XXX does Caldera support non Intel platforms ? If yes,
229 # where can we find the needed id ?
230 return 'OpenLinux',pkg[1],id
231
232 if os.path.isdir('/usr/lib/setup'):
233 # Check for slackware version tag file (thanks to Greg Andruk)
234 verfiles = os.listdir('/usr/lib/setup')
235 for n in range(len(verfiles)-1, -1, -1):
236 if verfiles[n][:14] != 'slack-version-':
237 del verfiles[n]
238 if verfiles:
239 verfiles.sort()
240 distname = 'slackware'
241 version = verfiles[-1][14:]
242 return distname,version,id
243
244 return distname,version,id
245
246_release_filename = re.compile(r'(\w+)[-_](release|version)')
247_lsb_release_version = re.compile(r'(.+)'
248 ' release '
249 '([\d.]+)'
250 '[^(]*(?:\((.+)\))?')
251_release_version = re.compile(r'([^0-9]+)'
252 '(?: release )?'
253 '([\d.]+)'
254 '[^(]*(?:\((.+)\))?')
255
256# See also http://www.novell.com/coolsolutions/feature/11251.html
257# and http://linuxmafia.com/faq/Admin/release-files.html
258# and http://data.linux-ntfs.org/rpm/whichrpm
259# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
260
261_supported_dists = (
262 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
263 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
264 'UnitedLinux', 'turbolinux')
265
266def _parse_release_file(firstline):
267
268 # Default to empty 'version' and 'id' strings. Both defaults are used
269 # when 'firstline' is empty. 'id' defaults to empty when an id can not
270 # be deduced.
271 version = ''
272 id = ''
273
274 # Parse the first line
275 m = _lsb_release_version.match(firstline)
276 if m is not None:
277 # LSB format: "distro release x.x (codename)"
278 return tuple(m.groups())
279
280 # Pre-LSB format: "distro x.x (codename)"
281 m = _release_version.match(firstline)
282 if m is not None:
283 return tuple(m.groups())
284
285 # Unknown format... take the first two words
286 l = string.split(string.strip(firstline))
287 if l:
288 version = l[0]
289 if len(l) > 1:
290 id = l[1]
291 return '', version, id
292
293def linux_distribution(distname='', version='', id='',
294
295 supported_dists=_supported_dists,
296 full_distribution_name=1):
297
298 """ Tries to determine the name of the Linux OS distribution name.
299
300 The function first looks for a distribution release file in
301 /etc and then reverts to _dist_try_harder() in case no
302 suitable files are found.
303
304 supported_dists may be given to define the set of Linux
305 distributions to look for. It defaults to a list of currently
306 supported Linux distributions identified by their release file
307 name.
308
309 If full_distribution_name is true (default), the full
310 distribution read from the OS is returned. Otherwise the short
311 name taken from supported_dists is used.
312
313 Returns a tuple (distname,version,id) which default to the
314 args given as parameters.
315
316 """
317 try:
318 etc = os.listdir('/etc')
319 except os.error:
320 # Probably not a Unix system
321 return distname,version,id
322 etc.sort()
323 for file in etc:
324 m = _release_filename.match(file)
325 if m is not None:
326 _distname,dummy = m.groups()
327 if _distname in supported_dists:
328 distname = _distname
329 break
330 else:
331 return _dist_try_harder(distname,version,id)
332
333 # Read the first line
334 f = open('/etc/'+file, 'r')
335 firstline = f.readline()
336 f.close()
337 _distname, _version, _id = _parse_release_file(firstline)
338
339 if _distname and full_distribution_name:
340 distname = _distname
341 if _version:
342 version = _version
343 if _id:
344 id = _id
345 return distname, version, id
346
347# To maintain backwards compatibility:
348
349def dist(distname='',version='',id='',
350
351 supported_dists=_supported_dists):
352
353 """ Tries to determine the name of the Linux OS distribution name.
354
355 The function first looks for a distribution release file in
356 /etc and then reverts to _dist_try_harder() in case no
357 suitable files are found.
358
359 Returns a tuple (distname,version,id) which default to the
360 args given as parameters.
361
362 """
363 return linux_distribution(distname, version, id,
364 supported_dists=supported_dists,
365 full_distribution_name=0)
366
367class _popen:
368
369 """ Fairly portable (alternative) popen implementation.
370
371 This is mostly needed in case os.popen() is not available, or
372 doesn't work as advertised, e.g. in Win9X GUI programs like
373 PythonWin or IDLE.
374
375 Writing to the pipe is currently not supported.
376
377 """
378 tmpfile = ''
379 pipe = None
380 bufsize = None
381 mode = 'r'
382
383 def __init__(self,cmd,mode='r',bufsize=None):
384
385 if mode != 'r':
386 raise ValueError,'popen()-emulation only supports read mode'
387 import tempfile
388 self.tmpfile = tmpfile = tempfile.mktemp()
389 os.system(cmd + ' > %s' % tmpfile)
390 self.pipe = open(tmpfile,'rb')
391 self.bufsize = bufsize
392 self.mode = mode
393
394 def read(self):
395
396 return self.pipe.read()
397
398 def readlines(self):
399
400 if self.bufsize is not None:
401 return self.pipe.readlines()
402
403 def close(self,
404
405 remove=os.unlink,error=os.error):
406
407 if self.pipe:
408 rc = self.pipe.close()
409 else:
410 rc = 255
411 if self.tmpfile:
412 try:
413 remove(self.tmpfile)
414 except error:
415 pass
416 return rc
417
418 # Alias
419 __del__ = close
420
421def popen(cmd, mode='r', bufsize=None):
422
423 """ Portable popen() interface.
424 """
425 # Find a working popen implementation preferring win32pipe.popen
426 # over os.popen over _popen
427 popen = None
428 if os.environ.get('OS','') == 'Windows_NT':
429 # On NT win32pipe should work; on Win9x it hangs due to bugs
430 # in the MS C lib (see MS KnowledgeBase article Q150956)
431 try:
432 import win32pipe
433 except ImportError:
434 pass
435 else:
436 popen = win32pipe.popen
437 if popen is None:
438 if hasattr(os,'popen'):
439 popen = os.popen
440 # Check whether it works... it doesn't in GUI programs
441 # on Windows platforms
442 if sys.platform == 'win32': # XXX Others too ?
443 try:
444 popen('')
445 except os.error:
446 popen = _popen
447 else:
448 popen = _popen
449 if bufsize is None:
450 return popen(cmd,mode)
451 else:
452 return popen(cmd,mode,bufsize)
453
454def _norm_version(version, build=''):
455
456 """ Normalize the version and build strings and return a single
457 version string using the format major.minor.build (or patchlevel).
458 """
459 l = string.split(version,'.')
460 if build:
461 l.append(build)
462 try:
463 ints = map(int,l)
464 except ValueError:
465 strings = l
466 else:
467 strings = map(str,ints)
468 version = string.join(strings[:3],'.')
469 return version
470
471_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
472 '.*'
473 '\[.* ([\d.]+)\])')
474
475# Examples of VER command output:
476#
477# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
478# Windows XP: Microsoft Windows XP [Version 5.1.2600]
479# Windows Vista: Microsoft Windows [Version 6.0.6002]
480#
481# Note that the "Version" string gets localized on different
482# Windows versions.
483
484def _syscmd_ver(system='', release='', version='',
485
486 supported_platforms=('win32','win16','dos','os2')):
487
488 """ Tries to figure out the OS version used and returns
489 a tuple (system,release,version).
490
491 It uses the "ver" shell command for this which is known
492 to exists on Windows, DOS and OS/2. XXX Others too ?
493
494 In case this fails, the given parameters are used as
495 defaults.
496
497 """
498 if sys.platform not in supported_platforms:
499 return system,release,version
500
501 # Try some common cmd strings
502 for cmd in ('ver','command /c ver','cmd /c ver'):
503 try:
504 pipe = popen(cmd)
505 info = pipe.read()
506 if pipe.close():
507 raise os.error,'command failed'
508 # XXX How can I suppress shell errors from being written
509 # to stderr ?
510 except os.error,why:
511 #print 'Command %s failed: %s' % (cmd,why)
512 continue
513 except IOError,why:
514 #print 'Command %s failed: %s' % (cmd,why)
515 continue
516 else:
517 break
518 else:
519 return system,release,version
520
521 # Parse the output
522 info = string.strip(info)
523 m = _ver_output.match(info)
524 if m is not None:
525 system,release,version = m.groups()
526 # Strip trailing dots from version and release
527 if release[-1] == '.':
528 release = release[:-1]
529 if version[-1] == '.':
530 version = version[:-1]
531 # Normalize the version and build strings (eliminating additional
532 # zeros)
533 version = _norm_version(version)
534 return system,release,version
535
536_WIN32_CLIENT_RELEASES = {
537 (5, 0): "2000",
538 (5, 1): "XP",
539 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
540 # has always called it 2003 Server
541 (5, 2): "2003Server",
542 (5, None): "post2003",
543
544 (6, 0): "Vista",
545 (6, 1): "7",
546 (6, 2): "8",
547 (6, 3): "8.1",
548 (6, None): "post8.1",
549
550 (10, 0): "10",
551 (10, None): "post10",
552}
553
554# Server release name lookup will default to client names if necessary
555_WIN32_SERVER_RELEASES = {
556 (5, 2): "2003Server",
557
558 (6, 0): "2008Server",
559 (6, 1): "2008ServerR2",
560 (6, 2): "2012Server",
561 (6, 3): "2012ServerR2",
562 (6, None): "post2012ServerR2",
563}
564
565def _get_real_winver(maj, min, build):
566 if maj < 6 or (maj == 6 and min < 2):
567 return maj, min, build
568
569 from ctypes import (c_buffer, POINTER, byref, create_unicode_buffer,
570 Structure, WinDLL, _Pointer)
571 from ctypes.wintypes import DWORD, HANDLE
572
573 class VS_FIXEDFILEINFO(Structure):
574 _fields_ = [
575 ("dwSignature", DWORD),
576 ("dwStrucVersion", DWORD),
577 ("dwFileVersionMS", DWORD),
578 ("dwFileVersionLS", DWORD),
579 ("dwProductVersionMS", DWORD),
580 ("dwProductVersionLS", DWORD),
581 ("dwFileFlagsMask", DWORD),
582 ("dwFileFlags", DWORD),
583 ("dwFileOS", DWORD),
584 ("dwFileType", DWORD),
585 ("dwFileSubtype", DWORD),
586 ("dwFileDateMS", DWORD),
587 ("dwFileDateLS", DWORD),
588 ]
589 class PVS_FIXEDFILEINFO(_Pointer):
590 _type_ = VS_FIXEDFILEINFO
591
592 kernel32 = WinDLL('kernel32')
593 version = WinDLL('version')
594
595 # We will immediately double the length up to MAX_PATH, but the
596 # path may be longer, so we retry until the returned string is
597 # shorter than our buffer.
598 name_len = actual_len = 130
599 while actual_len == name_len:
600 name_len *= 2
601 name = create_unicode_buffer(name_len)
602 actual_len = kernel32.GetModuleFileNameW(HANDLE(kernel32._handle),
603 name, len(name))
604 if not actual_len:
605 return maj, min, build
606
607 size = version.GetFileVersionInfoSizeW(name, None)
608 if not size:
609 return maj, min, build
610
611 ver_block = c_buffer(size)
612 if (not version.GetFileVersionInfoW(name, None, size, ver_block) or
613 not ver_block):
614 return maj, min, build
615
616 pvi = PVS_FIXEDFILEINFO()
617 if not version.VerQueryValueW(ver_block, "", byref(pvi), byref(DWORD())):
618 return maj, min, build
619
620 maj = pvi.contents.dwProductVersionMS >> 16
621 min = pvi.contents.dwProductVersionMS & 0xFFFF
622 build = pvi.contents.dwProductVersionLS >> 16
623
624 return maj, min, build
625
626def win32_ver(release='', version='', csd='', ptype=''):
627 try:
628 from sys import getwindowsversion
629 except ImportError:
630 return release, version, csd, ptype
631 try:
632 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
633 except ImportError:
634 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
635
636 winver = getwindowsversion()
637 maj, min, build = _get_real_winver(*winver[:3])
638 version = '{0}.{1}.{2}'.format(maj, min, build)
639
640 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
641 _WIN32_CLIENT_RELEASES.get((maj, None)) or
642 release)
643
644 # getwindowsversion() reflect the compatibility mode Python is
645 # running under, and so the service pack value is only going to be
646 # valid if the versions match.
647 if winver[:2] == (maj, min):
648 try:
649 csd = 'SP{}'.format(winver.service_pack_major)
650 except AttributeError:
651 if csd[:13] == 'Service Pack ':
652 csd = 'SP' + csd[13:]
653
654 # VER_NT_SERVER = 3
655 if getattr(winver, 'product_type', None) == 3:
656 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
657 _WIN32_SERVER_RELEASES.get((maj, None)) or
658 release)
659
660 key = None
661 try:
662 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
663 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
664 ptype = QueryValueEx(key, 'CurrentType')[0]
665 except:
666 pass
667 finally:
668 if key:
669 CloseKey(key)
670
671 return release, version, csd, ptype
672
673def _mac_ver_lookup(selectors,default=None):
674
675 from gestalt import gestalt
676 import MacOS
677 l = []
678 append = l.append
679 for selector in selectors:
680 try:
681 append(gestalt(selector))
682 except (RuntimeError, MacOS.Error):
683 append(default)
684 return l
685
686def _bcd2str(bcd):
687
688 return hex(bcd)[2:]
689
690def _mac_ver_gestalt():
691 """
692 Thanks to Mark R. Levinson for mailing documentation links and
693 code examples for this function. Documentation for the
694 gestalt() API is available online at:
695
696 http://www.rgaros.nl/gestalt/
697 """
698 # Check whether the version info module is available
699 try:
700 import gestalt
701 import MacOS
702 except ImportError:
703 return None
704 # Get the infos
705 sysv,sysa = _mac_ver_lookup(('sysv','sysa'))
706 # Decode the infos
707 if sysv:
708 major = (sysv & 0xFF00) >> 8
709 minor = (sysv & 0x00F0) >> 4
710 patch = (sysv & 0x000F)
711
712 if (major, minor) >= (10, 4):
713 # the 'sysv' gestald cannot return patchlevels
714 # higher than 9. Apple introduced 3 new
715 # gestalt codes in 10.4 to deal with this
716 # issue (needed because patch levels can
717 # run higher than 9, such as 10.4.11)
718 major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3'))
719 release = '%i.%i.%i' %(major, minor, patch)
720 else:
721 release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
722
723 if sysa:
724 machine = {0x1: '68k',
725 0x2: 'PowerPC',
726 0xa: 'i386'}.get(sysa,'')
727
728 versioninfo=('', '', '')
729 return release,versioninfo,machine
730
731def _mac_ver_xml():
732 fn = '/System/Library/CoreServices/SystemVersion.plist'
733 if not os.path.exists(fn):
734 return None
735
736 try:
737 import plistlib
738 except ImportError:
739 return None
740
741 pl = plistlib.readPlist(fn)
742 release = pl['ProductVersion']
743 versioninfo=('', '', '')
744 machine = os.uname()[4]
745 if machine in ('ppc', 'Power Macintosh'):
746 # for compatibility with the gestalt based code
747 machine = 'PowerPC'
748
749 return release,versioninfo,machine
750
751
752def mac_ver(release='',versioninfo=('','',''),machine=''):
753
754 """ Get MacOS version information and return it as tuple (release,
755 versioninfo, machine) with versioninfo being a tuple (version,
756 dev_stage, non_release_version).
757
758 Entries which cannot be determined are set to the parameter values
759 which default to ''. All tuple entries are strings.
760 """
761
762 # First try reading the information from an XML file which should
763 # always be present
764 info = _mac_ver_xml()
765 if info is not None:
766 return info
767
768 # If that doesn't work for some reason fall back to reading the
769 # information using gestalt calls.
770 info = _mac_ver_gestalt()
771 if info is not None:
772 return info
773
774 # If that also doesn't work return the default values
775 return release,versioninfo,machine
776
777def _java_getprop(name,default):
778
779 from java.lang import System
780 try:
781 value = System.getProperty(name)
782 if value is None:
783 return default
784 return value
785 except AttributeError:
786 return default
787
788def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
789
790 """ Version interface for Jython.
791
792 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
793 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
794 tuple (os_name,os_version,os_arch).
795
796 Values which cannot be determined are set to the defaults
797 given as parameters (which all default to '').
798
799 """
800 # Import the needed APIs
801 try:
802 import java.lang
803 except ImportError:
804 return release,vendor,vminfo,osinfo
805
806 vendor = _java_getprop('java.vendor', vendor)
807 release = _java_getprop('java.version', release)
808 vm_name, vm_release, vm_vendor = vminfo
809 vm_name = _java_getprop('java.vm.name', vm_name)
810 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
811 vm_release = _java_getprop('java.vm.version', vm_release)
812 vminfo = vm_name, vm_release, vm_vendor
813 os_name, os_version, os_arch = osinfo
814 os_arch = _java_getprop('java.os.arch', os_arch)
815 os_name = _java_getprop('java.os.name', os_name)
816 os_version = _java_getprop('java.os.version', os_version)
817 osinfo = os_name, os_version, os_arch
818
819 return release, vendor, vminfo, osinfo
820
821### System name aliasing
822
823def system_alias(system,release,version):
824
825 """ Returns (system,release,version) aliased to common
826 marketing names used for some systems.
827
828 It also does some reordering of the information in some cases
829 where it would otherwise cause confusion.
830
831 """
832 if system == 'Rhapsody':
833 # Apple's BSD derivative
834 # XXX How can we determine the marketing release number ?
835 return 'MacOS X Server',system+release,version
836
837 elif system == 'SunOS':
838 # Sun's OS
839 if release < '5':
840 # These releases use the old name SunOS
841 return system,release,version
842 # Modify release (marketing release = SunOS release - 3)
843 l = string.split(release,'.')
844 if l:
845 try:
846 major = int(l[0])
847 except ValueError:
848 pass
849 else:
850 major = major - 3
851 l[0] = str(major)
852 release = string.join(l,'.')
853 if release < '6':
854 system = 'Solaris'
855 else:
856 # XXX Whatever the new SunOS marketing name is...
857 system = 'Solaris'
858
859 elif system == 'IRIX64':
860 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
861 # is really a version and not a different platform, since 32-bit
862 # apps are also supported..
863 system = 'IRIX'
864 if version:
865 version = version + ' (64bit)'
866 else:
867 version = '64bit'
868
869 elif system in ('win32','win16'):
870 # In case one of the other tricks
871 system = 'Windows'
872
873 return system,release,version
874
875### Various internal helpers
876
877def _platform(*args):
878
879 """ Helper to format the platform string in a filename
880 compatible format e.g. "system-version-machine".
881 """
882 # Format the platform string
883 platform = string.join(
884 map(string.strip,
885 filter(len, args)),
886 '-')
887
888 # Cleanup some possible filename obstacles...
889 replace = string.replace
890 platform = replace(platform,' ','_')
891 platform = replace(platform,'/','-')
892 platform = replace(platform,'\\','-')
893 platform = replace(platform,':','-')
894 platform = replace(platform,';','-')
895 platform = replace(platform,'"','-')
896 platform = replace(platform,'(','-')
897 platform = replace(platform,')','-')
898
899 # No need to report 'unknown' information...
900 platform = replace(platform,'unknown','')
901
902 # Fold '--'s and remove trailing '-'
903 while 1:
904 cleaned = replace(platform,'--','-')
905 if cleaned == platform:
906 break
907 platform = cleaned
908 while platform[-1] == '-':
909 platform = platform[:-1]
910
911 return platform
912
913def _node(default=''):
914
915 """ Helper to determine the node name of this machine.
916 """
917 try:
918 import socket
919 except ImportError:
920 # No sockets...
921 return default
922 try:
923 return socket.gethostname()
924 except socket.error:
925 # Still not working...
926 return default
927
928# os.path.abspath is new in Python 1.5.2:
929if not hasattr(os.path,'abspath'):
930
931 def _abspath(path,
932
933 isabs=os.path.isabs,join=os.path.join,getcwd=os.getcwd,
934 normpath=os.path.normpath):
935
936 if not isabs(path):
937 path = join(getcwd(), path)
938 return normpath(path)
939
940else:
941
942 _abspath = os.path.abspath
943
944def _follow_symlinks(filepath):
945
946 """ In case filepath is a symlink, follow it until a
947 real file is reached.
948 """
949 filepath = _abspath(filepath)
950 while os.path.islink(filepath):
951 filepath = os.path.normpath(
952 os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
953 return filepath
954
955def _syscmd_uname(option,default=''):
956
957 """ Interface to the system's uname command.
958 """
959 if sys.platform in ('dos','win32','win16','os2'):
960 # XXX Others too ?
961 return default
962 try:
963 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
964 except (AttributeError,os.error):
965 return default
966 output = string.strip(f.read())
967 rc = f.close()
968 if not output or rc:
969 return default
970 else:
971 return output
972
973def _syscmd_file(target,default=''):
974
975 """ Interface to the system's file command.
976
977 The function uses the -b option of the file command to have it
978 omit the filename in its output and if possible the -L option
979 to have the command follow symlinks. It returns default in
980 case the command should fail.
981
982 """
983
984 # We do the import here to avoid a bootstrap issue.
985 # See c73b90b6dadd changeset.
986 #
987 # [..]
988 # ranlib libpython2.7.a
989 # gcc -o python \
990 # Modules/python.o \
991 # libpython2.7.a -lsocket -lnsl -ldl -lm
992 # Traceback (most recent call last):
993 # File "./setup.py", line 8, in <module>
994 # from platform import machine as platform_machine
995 # File "[..]/build/Lib/platform.py", line 116, in <module>
996 # import sys,string,os,re,subprocess
997 # File "[..]/build/Lib/subprocess.py", line 429, in <module>
998 # import select
999 # ImportError: No module named select
1000
1001 import subprocess
1002
1003 if sys.platform in ('dos','win32','win16','os2'):
1004 # XXX Others too ?
1005 return default
1006 target = _follow_symlinks(target)
1007 try:
1008 proc = subprocess.Popen(['file', target],
1009 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
1010
1011 except (AttributeError,os.error):
1012 return default
1013 output = proc.communicate()[0]
1014 rc = proc.wait()
1015 if not output or rc:
1016 return default
1017 else:
1018 return output
1019
1020### Information about the used architecture
1021
1022# Default values for architecture; non-empty strings override the
1023# defaults given as parameters
1024_default_architecture = {
1025 'win32': ('','WindowsPE'),
1026 'win16': ('','Windows'),
1027 'dos': ('','MSDOS'),
1028}
1029
1030_architecture_split = re.compile(r'[\s,]').split
1031
1032def architecture(executable=sys.executable,bits='',linkage=''):
1033
1034 """ Queries the given executable (defaults to the Python interpreter
1035 binary) for various architecture information.
1036
1037 Returns a tuple (bits,linkage) which contains information about
1038 the bit architecture and the linkage format used for the
1039 executable. Both values are returned as strings.
1040
1041 Values that cannot be determined are returned as given by the
1042 parameter presets. If bits is given as '', the sizeof(pointer)
1043 (or sizeof(long) on Python version < 1.5.2) is used as
1044 indicator for the supported pointer size.
1045
1046 The function relies on the system's "file" command to do the
1047 actual work. This is available on most if not all Unix
1048 platforms. On some non-Unix platforms where the "file" command
1049 does not exist and the executable is set to the Python interpreter
1050 binary defaults from _default_architecture are used.
1051
1052 """
1053 # Use the sizeof(pointer) as default number of bits if nothing
1054 # else is given as default.
1055 if not bits:
1056 import struct
1057 try:
1058 size = struct.calcsize('P')
1059 except struct.error:
1060 # Older installations can only query longs
1061 size = struct.calcsize('l')
1062 bits = str(size*8) + 'bit'
1063
1064 # Get data from the 'file' system command
1065 if executable:
1066 output = _syscmd_file(executable, '')
1067 else:
1068 output = ''
1069
1070 if not output and \
1071 executable == sys.executable:
1072 # "file" command did not return anything; we'll try to provide
1073 # some sensible defaults then...
1074 if sys.platform in _default_architecture:
1075 b, l = _default_architecture[sys.platform]
1076 if b:
1077 bits = b
1078 if l:
1079 linkage = l
1080 return bits, linkage
1081
1082 # Split the output into a list of strings omitting the filename
1083 fileout = _architecture_split(output)[1:]
1084
1085 if 'executable' not in fileout:
1086 # Format not supported
1087 return bits,linkage
1088
1089 # Bits
1090 if '32-bit' in fileout:
1091 bits = '32bit'
1092 elif 'N32' in fileout:
1093 # On Irix only
1094 bits = 'n32bit'
1095 elif '64-bit' in fileout:
1096 bits = '64bit'
1097
1098 # Linkage
1099 if 'ELF' in fileout:
1100 linkage = 'ELF'
1101 elif 'PE' in fileout:
1102 # E.g. Windows uses this format
1103 if 'Windows' in fileout:
1104 linkage = 'WindowsPE'
1105 else:
1106 linkage = 'PE'
1107 elif 'COFF' in fileout:
1108 linkage = 'COFF'
1109 elif 'MS-DOS' in fileout:
1110 linkage = 'MSDOS'
1111 else:
1112 # XXX the A.OUT format also falls under this class...
1113 pass
1114
1115 return bits,linkage
1116
1117### Portable uname() interface
1118
1119_uname_cache = None
1120
1121def uname():
1122
1123 """ Fairly portable uname interface. Returns a tuple
1124 of strings (system,node,release,version,machine,processor)
1125 identifying the underlying platform.
1126
1127 Note that unlike the os.uname function this also returns
1128 possible processor information as an additional tuple entry.
1129
1130 Entries which cannot be determined are set to ''.
1131
1132 """
1133 global _uname_cache
1134 no_os_uname = 0
1135
1136 if _uname_cache is not None:
1137 return _uname_cache
1138
1139 processor = ''
1140
1141 # Get some infos from the builtin os.uname API...
1142 try:
1143 system,node,release,version,machine = os.uname()
1144 except AttributeError:
1145 no_os_uname = 1
1146
1147 if no_os_uname or not filter(None, (system, node, release, version, machine)):
1148 # Hmm, no there is either no uname or uname has returned
1149 #'unknowns'... we'll have to poke around the system then.
1150 if no_os_uname:
1151 system = sys.platform
1152 release = ''
1153 version = ''
1154 node = _node()
1155 machine = ''
1156
1157 use_syscmd_ver = 1
1158
1159 # Try win32_ver() on win32 platforms
1160 if system == 'win32':
1161 release,version,csd,ptype = win32_ver()
1162 if release and version:
1163 use_syscmd_ver = 0
1164 # Try to use the PROCESSOR_* environment variables
1165 # available on Win XP and later; see
1166 # http://support.microsoft.com/kb/888731 and
1167 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
1168 if not machine:
1169 # WOW64 processes mask the native architecture
1170 if "PROCESSOR_ARCHITEW6432" in os.environ:
1171 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1172 else:
1173 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
1174 if not processor:
1175 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
1176
1177 # Try the 'ver' system command available on some
1178 # platforms
1179 if use_syscmd_ver:
1180 system,release,version = _syscmd_ver(system)
1181 # Normalize system to what win32_ver() normally returns
1182 # (_syscmd_ver() tends to return the vendor name as well)
1183 if system == 'Microsoft Windows':
1184 system = 'Windows'
1185 elif system == 'Microsoft' and release == 'Windows':
1186 # Under Windows Vista and Windows Server 2008,
1187 # Microsoft changed the output of the ver command. The
1188 # release is no longer printed. This causes the
1189 # system and release to be misidentified.
1190 system = 'Windows'
1191 if '6.0' == version[:3]:
1192 release = 'Vista'
1193 else:
1194 release = ''
1195
1196 # In case we still don't know anything useful, we'll try to
1197 # help ourselves
1198 if system in ('win32','win16'):
1199 if not version:
1200 if system == 'win32':
1201 version = '32bit'
1202 else:
1203 version = '16bit'
1204 system = 'Windows'
1205
1206 elif system[:4] == 'java':
1207 release,vendor,vminfo,osinfo = java_ver()
1208 system = 'Java'
1209 version = string.join(vminfo,', ')
1210 if not version:
1211 version = vendor
1212
1213 # System specific extensions
1214 if system == 'OpenVMS':
1215 # OpenVMS seems to have release and version mixed up
1216 if not release or release == '0':
1217 release = version
1218 version = ''
1219 # Get processor information
1220 try:
1221 import vms_lib
1222 except ImportError:
1223 pass
1224 else:
1225 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1226 if (cpu_number >= 128):
1227 processor = 'Alpha'
1228 else:
1229 processor = 'VAX'
1230 if not processor:
1231 # Get processor information from the uname system command
1232 processor = _syscmd_uname('-p','')
1233
1234 #If any unknowns still exist, replace them with ''s, which are more portable
1235 if system == 'unknown':
1236 system = ''
1237 if node == 'unknown':
1238 node = ''
1239 if release == 'unknown':
1240 release = ''
1241 if version == 'unknown':
1242 version = ''
1243 if machine == 'unknown':
1244 machine = ''
1245 if processor == 'unknown':
1246 processor = ''
1247
1248 # normalize name
1249 if system == 'Microsoft' and release == 'Windows':
1250 system = 'Windows'
1251 release = 'Vista'
1252
1253 _uname_cache = system,node,release,version,machine,processor
1254 return _uname_cache
1255
1256### Direct interfaces to some of the uname() return values
1257
1258def system():
1259
1260 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1261
1262 An empty string is returned if the value cannot be determined.
1263
1264 """
1265 return uname()[0]
1266
1267def node():
1268
1269 """ Returns the computer's network name (which may not be fully
1270 qualified)
1271
1272 An empty string is returned if the value cannot be determined.
1273
1274 """
1275 return uname()[1]
1276
1277def release():
1278
1279 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1280
1281 An empty string is returned if the value cannot be determined.
1282
1283 """
1284 return uname()[2]
1285
1286def version():
1287
1288 """ Returns the system's release version, e.g. '#3 on degas'
1289
1290 An empty string is returned if the value cannot be determined.
1291
1292 """
1293 return uname()[3]
1294
1295def machine():
1296
1297 """ Returns the machine type, e.g. 'i386'
1298
1299 An empty string is returned if the value cannot be determined.
1300
1301 """
1302 return uname()[4]
1303
1304def processor():
1305
1306 """ Returns the (true) processor name, e.g. 'amdk6'
1307
1308 An empty string is returned if the value cannot be
1309 determined. Note that many platforms do not provide this
1310 information or simply return the same value as for machine(),
1311 e.g. NetBSD does this.
1312
1313 """
1314 return uname()[5]
1315
1316### Various APIs for extracting information from sys.version
1317
1318_sys_version_parser = re.compile(
1319 r'([\w.+]+)\s*' # "version<space>"
1320 r'\(#?([^,]+)' # "(#buildno"
1321 r'(?:,\s*([\w ]*)' # ", builddate"
1322 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
1323 r'\[([^\]]+)\]?') # "[compiler]"
1324
1325_ironpython_sys_version_parser = re.compile(
1326 r'IronPython\s*'
1327 '([\d\.]+)'
1328 '(?: \(([\d\.]+)\))?'
1329 ' on (.NET [\d\.]+)')
1330
1331# IronPython covering 2.6 and 2.7
1332_ironpython26_sys_version_parser = re.compile(
1333 r'([\d.]+)\s*'
1334 '\(IronPython\s*'
1335 '[\d.]+\s*'
1336 '\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
1337)
1338
1339_pypy_sys_version_parser = re.compile(
1340 r'([\w.+]+)\s*'
1341 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1342 '\[PyPy [^\]]+\]?')
1343
1344_sys_version_cache = {}
1345
1346def _sys_version(sys_version=None):
1347
1348 """ Returns a parsed version of Python's sys.version as tuple
1349 (name, version, branch, revision, buildno, builddate, compiler)
1350 referring to the Python implementation name, version, branch,
1351 revision, build number, build date/time as string and the compiler
1352 identification string.
1353
1354 Note that unlike the Python sys.version, the returned value
1355 for the Python version will always include the patchlevel (it
1356 defaults to '.0').
1357
1358 The function returns empty strings for tuple entries that
1359 cannot be determined.
1360
1361 sys_version may be given to parse an alternative version
1362 string, e.g. if the version was read from a different Python
1363 interpreter.
1364
1365 """
1366 # Get the Python version
1367 if sys_version is None:
1368 sys_version = sys.version
1369
1370 # Try the cache first
1371 result = _sys_version_cache.get(sys_version, None)
1372 if result is not None:
1373 return result
1374
1375 # Parse it
1376 if 'IronPython' in sys_version:
1377 # IronPython
1378 name = 'IronPython'
1379 if sys_version.startswith('IronPython'):
1380 match = _ironpython_sys_version_parser.match(sys_version)
1381 else:
1382 match = _ironpython26_sys_version_parser.match(sys_version)
1383
1384 if match is None:
1385 raise ValueError(
1386 'failed to parse IronPython sys.version: %s' %
1387 repr(sys_version))
1388
1389 version, alt_version, compiler = match.groups()
1390 buildno = ''
1391 builddate = ''
1392
1393 elif sys.platform.startswith('java'):
1394 # Jython
1395 name = 'Jython'
1396 match = _sys_version_parser.match(sys_version)
1397 if match is None:
1398 raise ValueError(
1399 'failed to parse Jython sys.version: %s' %
1400 repr(sys_version))
1401 version, buildno, builddate, buildtime, _ = match.groups()
1402 if builddate is None:
1403 builddate = ''
1404 compiler = sys.platform
1405
1406 elif "PyPy" in sys_version:
1407 # PyPy
1408 name = "PyPy"
1409 match = _pypy_sys_version_parser.match(sys_version)
1410 if match is None:
1411 raise ValueError("failed to parse PyPy sys.version: %s" %
1412 repr(sys_version))
1413 version, buildno, builddate, buildtime = match.groups()
1414 compiler = ""
1415
1416 else:
1417 # CPython
1418 match = _sys_version_parser.match(sys_version)
1419 if match is None:
1420 raise ValueError(
1421 'failed to parse CPython sys.version: %s' %
1422 repr(sys_version))
1423 version, buildno, builddate, buildtime, compiler = \
1424 match.groups()
1425 name = 'CPython'
1426 if builddate is None:
1427 builddate = ''
1428 elif buildtime:
1429 builddate = builddate + ' ' + buildtime
1430
1431 if hasattr(sys, 'subversion'):
1432 # sys.subversion was added in Python 2.5
1433 _, branch, revision = sys.subversion
1434 else:
1435 branch = ''
1436 revision = ''
1437
1438 # Add the patchlevel version if missing
1439 l = string.split(version, '.')
1440 if len(l) == 2:
1441 l.append('0')
1442 version = string.join(l, '.')
1443
1444 # Build and cache the result
1445 result = (name, version, branch, revision, buildno, builddate, compiler)
1446 _sys_version_cache[sys_version] = result
1447 return result
1448
1449def python_implementation():
1450
1451 """ Returns a string identifying the Python implementation.
1452
1453 Currently, the following implementations are identified:
1454 'CPython' (C implementation of Python),
1455 'IronPython' (.NET implementation of Python),
1456 'Jython' (Java implementation of Python),
1457 'PyPy' (Python implementation of Python).
1458
1459 """
1460 # PATCH to identify OVM
1461 return 'OVM'
1462 #return _sys_version()[0]
1463
1464def python_version():
1465
1466 """ Returns the Python version as string 'major.minor.patchlevel'
1467
1468 Note that unlike the Python sys.version, the returned value
1469 will always include the patchlevel (it defaults to 0).
1470
1471 """
1472 return _sys_version()[1]
1473
1474def python_version_tuple():
1475
1476 """ Returns the Python version as tuple (major, minor, patchlevel)
1477 of strings.
1478
1479 Note that unlike the Python sys.version, the returned value
1480 will always include the patchlevel (it defaults to 0).
1481
1482 """
1483 return tuple(string.split(_sys_version()[1], '.'))
1484
1485def python_branch():
1486
1487 """ Returns a string identifying the Python implementation
1488 branch.
1489
1490 For CPython this is the Subversion branch from which the
1491 Python binary was built.
1492
1493 If not available, an empty string is returned.
1494
1495 """
1496
1497 return _sys_version()[2]
1498
1499def python_revision():
1500
1501 """ Returns a string identifying the Python implementation
1502 revision.
1503
1504 For CPython this is the Subversion revision from which the
1505 Python binary was built.
1506
1507 If not available, an empty string is returned.
1508
1509 """
1510 return _sys_version()[3]
1511
1512def python_build():
1513
1514 """ Returns a tuple (buildno, builddate) stating the Python
1515 build number and date as strings.
1516
1517 """
1518 return _sys_version()[4:6]
1519
1520def python_compiler():
1521
1522 """ Returns a string identifying the compiler used for compiling
1523 Python.
1524
1525 """
1526 return _sys_version()[6]
1527
1528### The Opus Magnum of platform strings :-)
1529
1530_platform_cache = {}
1531
1532def platform(aliased=0, terse=0):
1533
1534 """ Returns a single string identifying the underlying platform
1535 with as much useful information as possible (but no more :).
1536
1537 The output is intended to be human readable rather than
1538 machine parseable. It may look different on different
1539 platforms and this is intended.
1540
1541 If "aliased" is true, the function will use aliases for
1542 various platforms that report system names which differ from
1543 their common names, e.g. SunOS will be reported as
1544 Solaris. The system_alias() function is used to implement
1545 this.
1546
1547 Setting terse to true causes the function to return only the
1548 absolute minimum information needed to identify the platform.
1549
1550 """
1551 result = _platform_cache.get((aliased, terse), None)
1552 if result is not None:
1553 return result
1554
1555 # Get uname information and then apply platform specific cosmetics
1556 # to it...
1557 system,node,release,version,machine,processor = uname()
1558 if machine == processor:
1559 processor = ''
1560 if aliased:
1561 system,release,version = system_alias(system,release,version)
1562
1563 if system == 'Windows':
1564 # MS platforms
1565 rel,vers,csd,ptype = win32_ver(version)
1566 if terse:
1567 platform = _platform(system,release)
1568 else:
1569 platform = _platform(system,release,version,csd)
1570
1571 elif system in ('Linux',):
1572 # Linux based systems
1573 distname,distversion,distid = dist('')
1574 if distname and not terse:
1575 platform = _platform(system,release,machine,processor,
1576 'with',
1577 distname,distversion,distid)
1578 else:
1579 # If the distribution name is unknown check for libc vs. glibc
1580 libcname,libcversion = libc_ver(sys.executable)
1581 platform = _platform(system,release,machine,processor,
1582 'with',
1583 libcname+libcversion)
1584 elif system == 'Java':
1585 # Java platforms
1586 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
1587 if terse or not os_name:
1588 platform = _platform(system,release,version)
1589 else:
1590 platform = _platform(system,release,version,
1591 'on',
1592 os_name,os_version,os_arch)
1593
1594 elif system == 'MacOS':
1595 # MacOS platforms
1596 if terse:
1597 platform = _platform(system,release)
1598 else:
1599 platform = _platform(system,release,machine)
1600
1601 else:
1602 # Generic handler
1603 if terse:
1604 platform = _platform(system,release)
1605 else:
1606 bits,linkage = architecture(sys.executable)
1607 platform = _platform(system,release,machine,processor,bits,linkage)
1608
1609 _platform_cache[(aliased, terse)] = platform
1610 return platform
1611
1612### Command line interface
1613
1614if __name__ == '__main__':
1615 # Default is to print the aliased verbose platform string
1616 terse = ('terse' in sys.argv or '--terse' in sys.argv)
1617 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
1618 # Commented out because OPy compiler doesn't like print statements.
1619 #print platform(aliased,terse)
1620 sys.exit(0)