xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/platform.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*cda5da8dSAndroid Build Coastguard Worker
3*cda5da8dSAndroid Build Coastguard Worker""" This module tries to retrieve as much platform-identifying data as
4*cda5da8dSAndroid Build Coastguard Worker    possible. It makes this information available via function APIs.
5*cda5da8dSAndroid Build Coastguard Worker
6*cda5da8dSAndroid Build Coastguard Worker    If called from the command line, it prints the platform
7*cda5da8dSAndroid Build Coastguard Worker    information concatenated as single string to stdout. The output
8*cda5da8dSAndroid Build Coastguard Worker    format is usable as part of a filename.
9*cda5da8dSAndroid Build Coastguard Worker
10*cda5da8dSAndroid Build Coastguard Worker"""
11*cda5da8dSAndroid Build Coastguard Worker#    This module is maintained by Marc-Andre Lemburg <[email protected]>.
12*cda5da8dSAndroid Build Coastguard Worker#    If you find problems, please submit bug reports/patches via the
13*cda5da8dSAndroid Build Coastguard Worker#    Python bug tracker (http://bugs.python.org) and assign them to "lemburg".
14*cda5da8dSAndroid Build Coastguard Worker#
15*cda5da8dSAndroid Build Coastguard Worker#    Still needed:
16*cda5da8dSAndroid Build Coastguard Worker#    * support for MS-DOS (PythonDX ?)
17*cda5da8dSAndroid Build Coastguard Worker#    * support for Amiga and other still unsupported platforms running Python
18*cda5da8dSAndroid Build Coastguard Worker#    * support for additional Linux distributions
19*cda5da8dSAndroid Build Coastguard Worker#
20*cda5da8dSAndroid Build Coastguard Worker#    Many thanks to all those who helped adding platform-specific
21*cda5da8dSAndroid Build Coastguard Worker#    checks (in no particular order):
22*cda5da8dSAndroid Build Coastguard Worker#
23*cda5da8dSAndroid Build Coastguard Worker#      Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell,
24*cda5da8dSAndroid Build Coastguard Worker#      Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef
25*cda5da8dSAndroid Build Coastguard Worker#      Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
26*cda5da8dSAndroid Build Coastguard Worker#      Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
27*cda5da8dSAndroid Build Coastguard Worker#      Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
28*cda5da8dSAndroid Build Coastguard Worker#      Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter, Steve
29*cda5da8dSAndroid Build Coastguard Worker#      Dower
30*cda5da8dSAndroid Build Coastguard Worker#
31*cda5da8dSAndroid Build Coastguard Worker#    History:
32*cda5da8dSAndroid Build Coastguard Worker#
33*cda5da8dSAndroid Build Coastguard Worker#    <see CVS and SVN checkin messages for history>
34*cda5da8dSAndroid Build Coastguard Worker#
35*cda5da8dSAndroid Build Coastguard Worker#    1.0.8 - changed Windows support to read version from kernel32.dll
36*cda5da8dSAndroid Build Coastguard Worker#    1.0.7 - added DEV_NULL
37*cda5da8dSAndroid Build Coastguard Worker#    1.0.6 - added linux_distribution()
38*cda5da8dSAndroid Build Coastguard Worker#    1.0.5 - fixed Java support to allow running the module on Jython
39*cda5da8dSAndroid Build Coastguard Worker#    1.0.4 - added IronPython support
40*cda5da8dSAndroid Build Coastguard Worker#    1.0.3 - added normalization of Windows system name
41*cda5da8dSAndroid Build Coastguard Worker#    1.0.2 - added more Windows support
42*cda5da8dSAndroid Build Coastguard Worker#    1.0.1 - reformatted to make doc.py happy
43*cda5da8dSAndroid Build Coastguard Worker#    1.0.0 - reformatted a bit and checked into Python CVS
44*cda5da8dSAndroid Build Coastguard Worker#    0.8.0 - added sys.version parser and various new access
45*cda5da8dSAndroid Build Coastguard Worker#            APIs (python_version(), python_compiler(), etc.)
46*cda5da8dSAndroid Build Coastguard Worker#    0.7.2 - fixed architecture() to use sizeof(pointer) where available
47*cda5da8dSAndroid Build Coastguard Worker#    0.7.1 - added support for Caldera OpenLinux
48*cda5da8dSAndroid Build Coastguard Worker#    0.7.0 - some fixes for WinCE; untabified the source file
49*cda5da8dSAndroid Build Coastguard Worker#    0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
50*cda5da8dSAndroid Build Coastguard Worker#            vms_lib.getsyi() configured
51*cda5da8dSAndroid Build Coastguard Worker#    0.6.1 - added code to prevent 'uname -p' on platforms which are
52*cda5da8dSAndroid Build Coastguard Worker#            known not to support it
53*cda5da8dSAndroid Build Coastguard Worker#    0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
54*cda5da8dSAndroid Build Coastguard Worker#            did some cleanup of the interfaces - some APIs have changed
55*cda5da8dSAndroid Build Coastguard Worker#    0.5.5 - fixed another type in the MacOS code... should have
56*cda5da8dSAndroid Build Coastguard Worker#            used more coffee today ;-)
57*cda5da8dSAndroid Build Coastguard Worker#    0.5.4 - fixed a few typos in the MacOS code
58*cda5da8dSAndroid Build Coastguard Worker#    0.5.3 - added experimental MacOS support; added better popen()
59*cda5da8dSAndroid Build Coastguard Worker#            workarounds in _syscmd_ver() -- still not 100% elegant
60*cda5da8dSAndroid Build Coastguard Worker#            though
61*cda5da8dSAndroid Build Coastguard Worker#    0.5.2 - fixed uname() to return '' instead of 'unknown' in all
62*cda5da8dSAndroid Build Coastguard Worker#            return values (the system uname command tends to return
63*cda5da8dSAndroid Build Coastguard Worker#            'unknown' instead of just leaving the field empty)
64*cda5da8dSAndroid Build Coastguard Worker#    0.5.1 - included code for slackware dist; added exception handlers
65*cda5da8dSAndroid Build Coastguard Worker#            to cover up situations where platforms don't have os.popen
66*cda5da8dSAndroid Build Coastguard Worker#            (e.g. Mac) or fail on socket.gethostname(); fixed libc
67*cda5da8dSAndroid Build Coastguard Worker#            detection RE
68*cda5da8dSAndroid Build Coastguard Worker#    0.5.0 - changed the API names referring to system commands to *syscmd*;
69*cda5da8dSAndroid Build Coastguard Worker#            added java_ver(); made syscmd_ver() a private
70*cda5da8dSAndroid Build Coastguard Worker#            API (was system_ver() in previous versions) -- use uname()
71*cda5da8dSAndroid Build Coastguard Worker#            instead; extended the win32_ver() to also return processor
72*cda5da8dSAndroid Build Coastguard Worker#            type information
73*cda5da8dSAndroid Build Coastguard Worker#    0.4.0 - added win32_ver() and modified the platform() output for WinXX
74*cda5da8dSAndroid Build Coastguard Worker#    0.3.4 - fixed a bug in _follow_symlinks()
75*cda5da8dSAndroid Build Coastguard Worker#    0.3.3 - fixed popen() and "file" command invocation bugs
76*cda5da8dSAndroid Build Coastguard Worker#    0.3.2 - added architecture() API and support for it in platform()
77*cda5da8dSAndroid Build Coastguard Worker#    0.3.1 - fixed syscmd_ver() RE to support Windows NT
78*cda5da8dSAndroid Build Coastguard Worker#    0.3.0 - added system alias support
79*cda5da8dSAndroid Build Coastguard Worker#    0.2.3 - removed 'wince' again... oh well.
80*cda5da8dSAndroid Build Coastguard Worker#    0.2.2 - added 'wince' to syscmd_ver() supported platforms
81*cda5da8dSAndroid Build Coastguard Worker#    0.2.1 - added cache logic and changed the platform string format
82*cda5da8dSAndroid Build Coastguard Worker#    0.2.0 - changed the API to use functions instead of module globals
83*cda5da8dSAndroid Build Coastguard Worker#            since some action take too long to be run on module import
84*cda5da8dSAndroid Build Coastguard Worker#    0.1.0 - first release
85*cda5da8dSAndroid Build Coastguard Worker#
86*cda5da8dSAndroid Build Coastguard Worker#    You can always get the latest version of this module at:
87*cda5da8dSAndroid Build Coastguard Worker#
88*cda5da8dSAndroid Build Coastguard Worker#             http://www.egenix.com/files/python/platform.py
89*cda5da8dSAndroid Build Coastguard Worker#
90*cda5da8dSAndroid Build Coastguard Worker#    If that URL should fail, try contacting the author.
91*cda5da8dSAndroid Build Coastguard Worker
92*cda5da8dSAndroid Build Coastguard Worker__copyright__ = """
93*cda5da8dSAndroid Build Coastguard Worker    Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:[email protected]
94*cda5da8dSAndroid Build Coastguard Worker    Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:[email protected]
95*cda5da8dSAndroid Build Coastguard Worker
96*cda5da8dSAndroid Build Coastguard Worker    Permission to use, copy, modify, and distribute this software and its
97*cda5da8dSAndroid Build Coastguard Worker    documentation for any purpose and without fee or royalty is hereby granted,
98*cda5da8dSAndroid Build Coastguard Worker    provided that the above copyright notice appear in all copies and that
99*cda5da8dSAndroid Build Coastguard Worker    both that copyright notice and this permission notice appear in
100*cda5da8dSAndroid Build Coastguard Worker    supporting documentation or portions thereof, including modifications,
101*cda5da8dSAndroid Build Coastguard Worker    that you make.
102*cda5da8dSAndroid Build Coastguard Worker
103*cda5da8dSAndroid Build Coastguard Worker    EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
104*cda5da8dSAndroid Build Coastguard Worker    THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
105*cda5da8dSAndroid Build Coastguard Worker    FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
106*cda5da8dSAndroid Build Coastguard Worker    INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
107*cda5da8dSAndroid Build Coastguard Worker    FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
108*cda5da8dSAndroid Build Coastguard Worker    NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
109*cda5da8dSAndroid Build Coastguard Worker    WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
110*cda5da8dSAndroid Build Coastguard Worker
111*cda5da8dSAndroid Build Coastguard Worker"""
112*cda5da8dSAndroid Build Coastguard Worker
113*cda5da8dSAndroid Build Coastguard Worker__version__ = '1.0.8'
114*cda5da8dSAndroid Build Coastguard Worker
115*cda5da8dSAndroid Build Coastguard Workerimport collections
116*cda5da8dSAndroid Build Coastguard Workerimport os
117*cda5da8dSAndroid Build Coastguard Workerimport re
118*cda5da8dSAndroid Build Coastguard Workerimport sys
119*cda5da8dSAndroid Build Coastguard Workerimport functools
120*cda5da8dSAndroid Build Coastguard Workerimport itertools
121*cda5da8dSAndroid Build Coastguard Worker
122*cda5da8dSAndroid Build Coastguard Worker### Globals & Constants
123*cda5da8dSAndroid Build Coastguard Worker
124*cda5da8dSAndroid Build Coastguard Worker# Helper for comparing two version number strings.
125*cda5da8dSAndroid Build Coastguard Worker# Based on the description of the PHP's version_compare():
126*cda5da8dSAndroid Build Coastguard Worker# http://php.net/manual/en/function.version-compare.php
127*cda5da8dSAndroid Build Coastguard Worker
128*cda5da8dSAndroid Build Coastguard Worker_ver_stages = {
129*cda5da8dSAndroid Build Coastguard Worker    # any string not found in this dict, will get 0 assigned
130*cda5da8dSAndroid Build Coastguard Worker    'dev': 10,
131*cda5da8dSAndroid Build Coastguard Worker    'alpha': 20, 'a': 20,
132*cda5da8dSAndroid Build Coastguard Worker    'beta': 30, 'b': 30,
133*cda5da8dSAndroid Build Coastguard Worker    'c': 40,
134*cda5da8dSAndroid Build Coastguard Worker    'RC': 50, 'rc': 50,
135*cda5da8dSAndroid Build Coastguard Worker    # number, will get 100 assigned
136*cda5da8dSAndroid Build Coastguard Worker    'pl': 200, 'p': 200,
137*cda5da8dSAndroid Build Coastguard Worker}
138*cda5da8dSAndroid Build Coastguard Worker
139*cda5da8dSAndroid Build Coastguard Worker_component_re = re.compile(r'([0-9]+|[._+-])')
140*cda5da8dSAndroid Build Coastguard Worker
141*cda5da8dSAndroid Build Coastguard Workerdef _comparable_version(version):
142*cda5da8dSAndroid Build Coastguard Worker    result = []
143*cda5da8dSAndroid Build Coastguard Worker    for v in _component_re.split(version):
144*cda5da8dSAndroid Build Coastguard Worker        if v not in '._+-':
145*cda5da8dSAndroid Build Coastguard Worker            try:
146*cda5da8dSAndroid Build Coastguard Worker                v = int(v, 10)
147*cda5da8dSAndroid Build Coastguard Worker                t = 100
148*cda5da8dSAndroid Build Coastguard Worker            except ValueError:
149*cda5da8dSAndroid Build Coastguard Worker                t = _ver_stages.get(v, 0)
150*cda5da8dSAndroid Build Coastguard Worker            result.extend((t, v))
151*cda5da8dSAndroid Build Coastguard Worker    return result
152*cda5da8dSAndroid Build Coastguard Worker
153*cda5da8dSAndroid Build Coastguard Worker### Platform specific APIs
154*cda5da8dSAndroid Build Coastguard Worker
155*cda5da8dSAndroid Build Coastguard Worker_libc_search = re.compile(b'(__libc_init)'
156*cda5da8dSAndroid Build Coastguard Worker                          b'|'
157*cda5da8dSAndroid Build Coastguard Worker                          b'(GLIBC_([0-9.]+))'
158*cda5da8dSAndroid Build Coastguard Worker                          b'|'
159*cda5da8dSAndroid Build Coastguard Worker                          br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
160*cda5da8dSAndroid Build Coastguard Worker
161*cda5da8dSAndroid Build Coastguard Workerdef libc_ver(executable=None, lib='', version='', chunksize=16384):
162*cda5da8dSAndroid Build Coastguard Worker
163*cda5da8dSAndroid Build Coastguard Worker    """ Tries to determine the libc version that the file executable
164*cda5da8dSAndroid Build Coastguard Worker        (which defaults to the Python interpreter) is linked against.
165*cda5da8dSAndroid Build Coastguard Worker
166*cda5da8dSAndroid Build Coastguard Worker        Returns a tuple of strings (lib,version) which default to the
167*cda5da8dSAndroid Build Coastguard Worker        given parameters in case the lookup fails.
168*cda5da8dSAndroid Build Coastguard Worker
169*cda5da8dSAndroid Build Coastguard Worker        Note that the function has intimate knowledge of how different
170*cda5da8dSAndroid Build Coastguard Worker        libc versions add symbols to the executable and thus is probably
171*cda5da8dSAndroid Build Coastguard Worker        only usable for executables compiled using gcc.
172*cda5da8dSAndroid Build Coastguard Worker
173*cda5da8dSAndroid Build Coastguard Worker        The file is read and scanned in chunks of chunksize bytes.
174*cda5da8dSAndroid Build Coastguard Worker
175*cda5da8dSAndroid Build Coastguard Worker    """
176*cda5da8dSAndroid Build Coastguard Worker    if not executable:
177*cda5da8dSAndroid Build Coastguard Worker        try:
178*cda5da8dSAndroid Build Coastguard Worker            ver = os.confstr('CS_GNU_LIBC_VERSION')
179*cda5da8dSAndroid Build Coastguard Worker            # parse 'glibc 2.28' as ('glibc', '2.28')
180*cda5da8dSAndroid Build Coastguard Worker            parts = ver.split(maxsplit=1)
181*cda5da8dSAndroid Build Coastguard Worker            if len(parts) == 2:
182*cda5da8dSAndroid Build Coastguard Worker                return tuple(parts)
183*cda5da8dSAndroid Build Coastguard Worker        except (AttributeError, ValueError, OSError):
184*cda5da8dSAndroid Build Coastguard Worker            # os.confstr() or CS_GNU_LIBC_VERSION value not available
185*cda5da8dSAndroid Build Coastguard Worker            pass
186*cda5da8dSAndroid Build Coastguard Worker
187*cda5da8dSAndroid Build Coastguard Worker        executable = sys.executable
188*cda5da8dSAndroid Build Coastguard Worker
189*cda5da8dSAndroid Build Coastguard Worker        if not executable:
190*cda5da8dSAndroid Build Coastguard Worker            # sys.executable is not set.
191*cda5da8dSAndroid Build Coastguard Worker            return lib, version
192*cda5da8dSAndroid Build Coastguard Worker
193*cda5da8dSAndroid Build Coastguard Worker    V = _comparable_version
194*cda5da8dSAndroid Build Coastguard Worker    # We use os.path.realpath()
195*cda5da8dSAndroid Build Coastguard Worker    # here to work around problems with Cygwin not being
196*cda5da8dSAndroid Build Coastguard Worker    # able to open symlinks for reading
197*cda5da8dSAndroid Build Coastguard Worker    executable = os.path.realpath(executable)
198*cda5da8dSAndroid Build Coastguard Worker    with open(executable, 'rb') as f:
199*cda5da8dSAndroid Build Coastguard Worker        binary = f.read(chunksize)
200*cda5da8dSAndroid Build Coastguard Worker        pos = 0
201*cda5da8dSAndroid Build Coastguard Worker        while pos < len(binary):
202*cda5da8dSAndroid Build Coastguard Worker            if b'libc' in binary or b'GLIBC' in binary:
203*cda5da8dSAndroid Build Coastguard Worker                m = _libc_search.search(binary, pos)
204*cda5da8dSAndroid Build Coastguard Worker            else:
205*cda5da8dSAndroid Build Coastguard Worker                m = None
206*cda5da8dSAndroid Build Coastguard Worker            if not m or m.end() == len(binary):
207*cda5da8dSAndroid Build Coastguard Worker                chunk = f.read(chunksize)
208*cda5da8dSAndroid Build Coastguard Worker                if chunk:
209*cda5da8dSAndroid Build Coastguard Worker                    binary = binary[max(pos, len(binary) - 1000):] + chunk
210*cda5da8dSAndroid Build Coastguard Worker                    pos = 0
211*cda5da8dSAndroid Build Coastguard Worker                    continue
212*cda5da8dSAndroid Build Coastguard Worker                if not m:
213*cda5da8dSAndroid Build Coastguard Worker                    break
214*cda5da8dSAndroid Build Coastguard Worker            libcinit, glibc, glibcversion, so, threads, soversion = [
215*cda5da8dSAndroid Build Coastguard Worker                s.decode('latin1') if s is not None else s
216*cda5da8dSAndroid Build Coastguard Worker                for s in m.groups()]
217*cda5da8dSAndroid Build Coastguard Worker            if libcinit and not lib:
218*cda5da8dSAndroid Build Coastguard Worker                lib = 'libc'
219*cda5da8dSAndroid Build Coastguard Worker            elif glibc:
220*cda5da8dSAndroid Build Coastguard Worker                if lib != 'glibc':
221*cda5da8dSAndroid Build Coastguard Worker                    lib = 'glibc'
222*cda5da8dSAndroid Build Coastguard Worker                    version = glibcversion
223*cda5da8dSAndroid Build Coastguard Worker                elif V(glibcversion) > V(version):
224*cda5da8dSAndroid Build Coastguard Worker                    version = glibcversion
225*cda5da8dSAndroid Build Coastguard Worker            elif so:
226*cda5da8dSAndroid Build Coastguard Worker                if lib != 'glibc':
227*cda5da8dSAndroid Build Coastguard Worker                    lib = 'libc'
228*cda5da8dSAndroid Build Coastguard Worker                    if soversion and (not version or V(soversion) > V(version)):
229*cda5da8dSAndroid Build Coastguard Worker                        version = soversion
230*cda5da8dSAndroid Build Coastguard Worker                    if threads and version[-len(threads):] != threads:
231*cda5da8dSAndroid Build Coastguard Worker                        version = version + threads
232*cda5da8dSAndroid Build Coastguard Worker            pos = m.end()
233*cda5da8dSAndroid Build Coastguard Worker    return lib, version
234*cda5da8dSAndroid Build Coastguard Worker
235*cda5da8dSAndroid Build Coastguard Workerdef _norm_version(version, build=''):
236*cda5da8dSAndroid Build Coastguard Worker
237*cda5da8dSAndroid Build Coastguard Worker    """ Normalize the version and build strings and return a single
238*cda5da8dSAndroid Build Coastguard Worker        version string using the format major.minor.build (or patchlevel).
239*cda5da8dSAndroid Build Coastguard Worker    """
240*cda5da8dSAndroid Build Coastguard Worker    l = version.split('.')
241*cda5da8dSAndroid Build Coastguard Worker    if build:
242*cda5da8dSAndroid Build Coastguard Worker        l.append(build)
243*cda5da8dSAndroid Build Coastguard Worker    try:
244*cda5da8dSAndroid Build Coastguard Worker        strings = list(map(str, map(int, l)))
245*cda5da8dSAndroid Build Coastguard Worker    except ValueError:
246*cda5da8dSAndroid Build Coastguard Worker        strings = l
247*cda5da8dSAndroid Build Coastguard Worker    version = '.'.join(strings[:3])
248*cda5da8dSAndroid Build Coastguard Worker    return version
249*cda5da8dSAndroid Build Coastguard Worker
250*cda5da8dSAndroid Build Coastguard Worker_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
251*cda5da8dSAndroid Build Coastguard Worker                         r'.*'
252*cda5da8dSAndroid Build Coastguard Worker                         r'\[.* ([\d.]+)\])')
253*cda5da8dSAndroid Build Coastguard Worker
254*cda5da8dSAndroid Build Coastguard Worker# Examples of VER command output:
255*cda5da8dSAndroid Build Coastguard Worker#
256*cda5da8dSAndroid Build Coastguard Worker#   Windows 2000:  Microsoft Windows 2000 [Version 5.00.2195]
257*cda5da8dSAndroid Build Coastguard Worker#   Windows XP:    Microsoft Windows XP [Version 5.1.2600]
258*cda5da8dSAndroid Build Coastguard Worker#   Windows Vista: Microsoft Windows [Version 6.0.6002]
259*cda5da8dSAndroid Build Coastguard Worker#
260*cda5da8dSAndroid Build Coastguard Worker# Note that the "Version" string gets localized on different
261*cda5da8dSAndroid Build Coastguard Worker# Windows versions.
262*cda5da8dSAndroid Build Coastguard Worker
263*cda5da8dSAndroid Build Coastguard Workerdef _syscmd_ver(system='', release='', version='',
264*cda5da8dSAndroid Build Coastguard Worker
265*cda5da8dSAndroid Build Coastguard Worker               supported_platforms=('win32', 'win16', 'dos')):
266*cda5da8dSAndroid Build Coastguard Worker
267*cda5da8dSAndroid Build Coastguard Worker    """ Tries to figure out the OS version used and returns
268*cda5da8dSAndroid Build Coastguard Worker        a tuple (system, release, version).
269*cda5da8dSAndroid Build Coastguard Worker
270*cda5da8dSAndroid Build Coastguard Worker        It uses the "ver" shell command for this which is known
271*cda5da8dSAndroid Build Coastguard Worker        to exists on Windows, DOS. XXX Others too ?
272*cda5da8dSAndroid Build Coastguard Worker
273*cda5da8dSAndroid Build Coastguard Worker        In case this fails, the given parameters are used as
274*cda5da8dSAndroid Build Coastguard Worker        defaults.
275*cda5da8dSAndroid Build Coastguard Worker
276*cda5da8dSAndroid Build Coastguard Worker    """
277*cda5da8dSAndroid Build Coastguard Worker    if sys.platform not in supported_platforms:
278*cda5da8dSAndroid Build Coastguard Worker        return system, release, version
279*cda5da8dSAndroid Build Coastguard Worker
280*cda5da8dSAndroid Build Coastguard Worker    # Try some common cmd strings
281*cda5da8dSAndroid Build Coastguard Worker    import subprocess
282*cda5da8dSAndroid Build Coastguard Worker    for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
283*cda5da8dSAndroid Build Coastguard Worker        try:
284*cda5da8dSAndroid Build Coastguard Worker            info = subprocess.check_output(cmd,
285*cda5da8dSAndroid Build Coastguard Worker                                           stdin=subprocess.DEVNULL,
286*cda5da8dSAndroid Build Coastguard Worker                                           stderr=subprocess.DEVNULL,
287*cda5da8dSAndroid Build Coastguard Worker                                           text=True,
288*cda5da8dSAndroid Build Coastguard Worker                                           encoding="locale",
289*cda5da8dSAndroid Build Coastguard Worker                                           shell=True)
290*cda5da8dSAndroid Build Coastguard Worker        except (OSError, subprocess.CalledProcessError) as why:
291*cda5da8dSAndroid Build Coastguard Worker            #print('Command %s failed: %s' % (cmd, why))
292*cda5da8dSAndroid Build Coastguard Worker            continue
293*cda5da8dSAndroid Build Coastguard Worker        else:
294*cda5da8dSAndroid Build Coastguard Worker            break
295*cda5da8dSAndroid Build Coastguard Worker    else:
296*cda5da8dSAndroid Build Coastguard Worker        return system, release, version
297*cda5da8dSAndroid Build Coastguard Worker
298*cda5da8dSAndroid Build Coastguard Worker    # Parse the output
299*cda5da8dSAndroid Build Coastguard Worker    info = info.strip()
300*cda5da8dSAndroid Build Coastguard Worker    m = _ver_output.match(info)
301*cda5da8dSAndroid Build Coastguard Worker    if m is not None:
302*cda5da8dSAndroid Build Coastguard Worker        system, release, version = m.groups()
303*cda5da8dSAndroid Build Coastguard Worker        # Strip trailing dots from version and release
304*cda5da8dSAndroid Build Coastguard Worker        if release[-1] == '.':
305*cda5da8dSAndroid Build Coastguard Worker            release = release[:-1]
306*cda5da8dSAndroid Build Coastguard Worker        if version[-1] == '.':
307*cda5da8dSAndroid Build Coastguard Worker            version = version[:-1]
308*cda5da8dSAndroid Build Coastguard Worker        # Normalize the version and build strings (eliminating additional
309*cda5da8dSAndroid Build Coastguard Worker        # zeros)
310*cda5da8dSAndroid Build Coastguard Worker        version = _norm_version(version)
311*cda5da8dSAndroid Build Coastguard Worker    return system, release, version
312*cda5da8dSAndroid Build Coastguard Worker
313*cda5da8dSAndroid Build Coastguard Worker_WIN32_CLIENT_RELEASES = {
314*cda5da8dSAndroid Build Coastguard Worker    (5, 0): "2000",
315*cda5da8dSAndroid Build Coastguard Worker    (5, 1): "XP",
316*cda5da8dSAndroid Build Coastguard Worker    # Strictly, 5.2 client is XP 64-bit, but platform.py historically
317*cda5da8dSAndroid Build Coastguard Worker    # has always called it 2003 Server
318*cda5da8dSAndroid Build Coastguard Worker    (5, 2): "2003Server",
319*cda5da8dSAndroid Build Coastguard Worker    (5, None): "post2003",
320*cda5da8dSAndroid Build Coastguard Worker
321*cda5da8dSAndroid Build Coastguard Worker    (6, 0): "Vista",
322*cda5da8dSAndroid Build Coastguard Worker    (6, 1): "7",
323*cda5da8dSAndroid Build Coastguard Worker    (6, 2): "8",
324*cda5da8dSAndroid Build Coastguard Worker    (6, 3): "8.1",
325*cda5da8dSAndroid Build Coastguard Worker    (6, None): "post8.1",
326*cda5da8dSAndroid Build Coastguard Worker
327*cda5da8dSAndroid Build Coastguard Worker    (10, 0): "10",
328*cda5da8dSAndroid Build Coastguard Worker    (10, None): "post10",
329*cda5da8dSAndroid Build Coastguard Worker}
330*cda5da8dSAndroid Build Coastguard Worker
331*cda5da8dSAndroid Build Coastguard Worker# Server release name lookup will default to client names if necessary
332*cda5da8dSAndroid Build Coastguard Worker_WIN32_SERVER_RELEASES = {
333*cda5da8dSAndroid Build Coastguard Worker    (5, 2): "2003Server",
334*cda5da8dSAndroid Build Coastguard Worker
335*cda5da8dSAndroid Build Coastguard Worker    (6, 0): "2008Server",
336*cda5da8dSAndroid Build Coastguard Worker    (6, 1): "2008ServerR2",
337*cda5da8dSAndroid Build Coastguard Worker    (6, 2): "2012Server",
338*cda5da8dSAndroid Build Coastguard Worker    (6, 3): "2012ServerR2",
339*cda5da8dSAndroid Build Coastguard Worker    (6, None): "post2012ServerR2",
340*cda5da8dSAndroid Build Coastguard Worker}
341*cda5da8dSAndroid Build Coastguard Worker
342*cda5da8dSAndroid Build Coastguard Workerdef win32_is_iot():
343*cda5da8dSAndroid Build Coastguard Worker    return win32_edition() in ('IoTUAP', 'NanoServer', 'WindowsCoreHeadless', 'IoTEdgeOS')
344*cda5da8dSAndroid Build Coastguard Worker
345*cda5da8dSAndroid Build Coastguard Workerdef win32_edition():
346*cda5da8dSAndroid Build Coastguard Worker    try:
347*cda5da8dSAndroid Build Coastguard Worker        try:
348*cda5da8dSAndroid Build Coastguard Worker            import winreg
349*cda5da8dSAndroid Build Coastguard Worker        except ImportError:
350*cda5da8dSAndroid Build Coastguard Worker            import _winreg as winreg
351*cda5da8dSAndroid Build Coastguard Worker    except ImportError:
352*cda5da8dSAndroid Build Coastguard Worker        pass
353*cda5da8dSAndroid Build Coastguard Worker    else:
354*cda5da8dSAndroid Build Coastguard Worker        try:
355*cda5da8dSAndroid Build Coastguard Worker            cvkey = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion'
356*cda5da8dSAndroid Build Coastguard Worker            with winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE, cvkey) as key:
357*cda5da8dSAndroid Build Coastguard Worker                return winreg.QueryValueEx(key, 'EditionId')[0]
358*cda5da8dSAndroid Build Coastguard Worker        except OSError:
359*cda5da8dSAndroid Build Coastguard Worker            pass
360*cda5da8dSAndroid Build Coastguard Worker
361*cda5da8dSAndroid Build Coastguard Worker    return None
362*cda5da8dSAndroid Build Coastguard Worker
363*cda5da8dSAndroid Build Coastguard Workerdef win32_ver(release='', version='', csd='', ptype=''):
364*cda5da8dSAndroid Build Coastguard Worker    try:
365*cda5da8dSAndroid Build Coastguard Worker        from sys import getwindowsversion
366*cda5da8dSAndroid Build Coastguard Worker    except ImportError:
367*cda5da8dSAndroid Build Coastguard Worker        return release, version, csd, ptype
368*cda5da8dSAndroid Build Coastguard Worker
369*cda5da8dSAndroid Build Coastguard Worker    winver = getwindowsversion()
370*cda5da8dSAndroid Build Coastguard Worker    try:
371*cda5da8dSAndroid Build Coastguard Worker        major, minor, build = map(int, _syscmd_ver()[2].split('.'))
372*cda5da8dSAndroid Build Coastguard Worker    except ValueError:
373*cda5da8dSAndroid Build Coastguard Worker        major, minor, build = winver.platform_version or winver[:3]
374*cda5da8dSAndroid Build Coastguard Worker    version = '{0}.{1}.{2}'.format(major, minor, build)
375*cda5da8dSAndroid Build Coastguard Worker
376*cda5da8dSAndroid Build Coastguard Worker    release = (_WIN32_CLIENT_RELEASES.get((major, minor)) or
377*cda5da8dSAndroid Build Coastguard Worker               _WIN32_CLIENT_RELEASES.get((major, None)) or
378*cda5da8dSAndroid Build Coastguard Worker               release)
379*cda5da8dSAndroid Build Coastguard Worker
380*cda5da8dSAndroid Build Coastguard Worker    # getwindowsversion() reflect the compatibility mode Python is
381*cda5da8dSAndroid Build Coastguard Worker    # running under, and so the service pack value is only going to be
382*cda5da8dSAndroid Build Coastguard Worker    # valid if the versions match.
383*cda5da8dSAndroid Build Coastguard Worker    if winver[:2] == (major, minor):
384*cda5da8dSAndroid Build Coastguard Worker        try:
385*cda5da8dSAndroid Build Coastguard Worker            csd = 'SP{}'.format(winver.service_pack_major)
386*cda5da8dSAndroid Build Coastguard Worker        except AttributeError:
387*cda5da8dSAndroid Build Coastguard Worker            if csd[:13] == 'Service Pack ':
388*cda5da8dSAndroid Build Coastguard Worker                csd = 'SP' + csd[13:]
389*cda5da8dSAndroid Build Coastguard Worker
390*cda5da8dSAndroid Build Coastguard Worker    # VER_NT_SERVER = 3
391*cda5da8dSAndroid Build Coastguard Worker    if getattr(winver, 'product_type', None) == 3:
392*cda5da8dSAndroid Build Coastguard Worker        release = (_WIN32_SERVER_RELEASES.get((major, minor)) or
393*cda5da8dSAndroid Build Coastguard Worker                   _WIN32_SERVER_RELEASES.get((major, None)) or
394*cda5da8dSAndroid Build Coastguard Worker                   release)
395*cda5da8dSAndroid Build Coastguard Worker
396*cda5da8dSAndroid Build Coastguard Worker    try:
397*cda5da8dSAndroid Build Coastguard Worker        try:
398*cda5da8dSAndroid Build Coastguard Worker            import winreg
399*cda5da8dSAndroid Build Coastguard Worker        except ImportError:
400*cda5da8dSAndroid Build Coastguard Worker            import _winreg as winreg
401*cda5da8dSAndroid Build Coastguard Worker    except ImportError:
402*cda5da8dSAndroid Build Coastguard Worker        pass
403*cda5da8dSAndroid Build Coastguard Worker    else:
404*cda5da8dSAndroid Build Coastguard Worker        try:
405*cda5da8dSAndroid Build Coastguard Worker            cvkey = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion'
406*cda5da8dSAndroid Build Coastguard Worker            with winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE, cvkey) as key:
407*cda5da8dSAndroid Build Coastguard Worker                ptype = winreg.QueryValueEx(key, 'CurrentType')[0]
408*cda5da8dSAndroid Build Coastguard Worker        except OSError:
409*cda5da8dSAndroid Build Coastguard Worker            pass
410*cda5da8dSAndroid Build Coastguard Worker
411*cda5da8dSAndroid Build Coastguard Worker    return release, version, csd, ptype
412*cda5da8dSAndroid Build Coastguard Worker
413*cda5da8dSAndroid Build Coastguard Worker
414*cda5da8dSAndroid Build Coastguard Workerdef _mac_ver_xml():
415*cda5da8dSAndroid Build Coastguard Worker    fn = '/System/Library/CoreServices/SystemVersion.plist'
416*cda5da8dSAndroid Build Coastguard Worker    if not os.path.exists(fn):
417*cda5da8dSAndroid Build Coastguard Worker        return None
418*cda5da8dSAndroid Build Coastguard Worker
419*cda5da8dSAndroid Build Coastguard Worker    try:
420*cda5da8dSAndroid Build Coastguard Worker        import plistlib
421*cda5da8dSAndroid Build Coastguard Worker    except ImportError:
422*cda5da8dSAndroid Build Coastguard Worker        return None
423*cda5da8dSAndroid Build Coastguard Worker
424*cda5da8dSAndroid Build Coastguard Worker    with open(fn, 'rb') as f:
425*cda5da8dSAndroid Build Coastguard Worker        pl = plistlib.load(f)
426*cda5da8dSAndroid Build Coastguard Worker    release = pl['ProductVersion']
427*cda5da8dSAndroid Build Coastguard Worker    versioninfo = ('', '', '')
428*cda5da8dSAndroid Build Coastguard Worker    machine = os.uname().machine
429*cda5da8dSAndroid Build Coastguard Worker    if machine in ('ppc', 'Power Macintosh'):
430*cda5da8dSAndroid Build Coastguard Worker        # Canonical name
431*cda5da8dSAndroid Build Coastguard Worker        machine = 'PowerPC'
432*cda5da8dSAndroid Build Coastguard Worker
433*cda5da8dSAndroid Build Coastguard Worker    return release, versioninfo, machine
434*cda5da8dSAndroid Build Coastguard Worker
435*cda5da8dSAndroid Build Coastguard Worker
436*cda5da8dSAndroid Build Coastguard Workerdef mac_ver(release='', versioninfo=('', '', ''), machine=''):
437*cda5da8dSAndroid Build Coastguard Worker
438*cda5da8dSAndroid Build Coastguard Worker    """ Get macOS version information and return it as tuple (release,
439*cda5da8dSAndroid Build Coastguard Worker        versioninfo, machine) with versioninfo being a tuple (version,
440*cda5da8dSAndroid Build Coastguard Worker        dev_stage, non_release_version).
441*cda5da8dSAndroid Build Coastguard Worker
442*cda5da8dSAndroid Build Coastguard Worker        Entries which cannot be determined are set to the parameter values
443*cda5da8dSAndroid Build Coastguard Worker        which default to ''. All tuple entries are strings.
444*cda5da8dSAndroid Build Coastguard Worker    """
445*cda5da8dSAndroid Build Coastguard Worker
446*cda5da8dSAndroid Build Coastguard Worker    # First try reading the information from an XML file which should
447*cda5da8dSAndroid Build Coastguard Worker    # always be present
448*cda5da8dSAndroid Build Coastguard Worker    info = _mac_ver_xml()
449*cda5da8dSAndroid Build Coastguard Worker    if info is not None:
450*cda5da8dSAndroid Build Coastguard Worker        return info
451*cda5da8dSAndroid Build Coastguard Worker
452*cda5da8dSAndroid Build Coastguard Worker    # If that also doesn't work return the default values
453*cda5da8dSAndroid Build Coastguard Worker    return release, versioninfo, machine
454*cda5da8dSAndroid Build Coastguard Worker
455*cda5da8dSAndroid Build Coastguard Workerdef _java_getprop(name, default):
456*cda5da8dSAndroid Build Coastguard Worker
457*cda5da8dSAndroid Build Coastguard Worker    from java.lang import System
458*cda5da8dSAndroid Build Coastguard Worker    try:
459*cda5da8dSAndroid Build Coastguard Worker        value = System.getProperty(name)
460*cda5da8dSAndroid Build Coastguard Worker        if value is None:
461*cda5da8dSAndroid Build Coastguard Worker            return default
462*cda5da8dSAndroid Build Coastguard Worker        return value
463*cda5da8dSAndroid Build Coastguard Worker    except AttributeError:
464*cda5da8dSAndroid Build Coastguard Worker        return default
465*cda5da8dSAndroid Build Coastguard Worker
466*cda5da8dSAndroid Build Coastguard Workerdef java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
467*cda5da8dSAndroid Build Coastguard Worker
468*cda5da8dSAndroid Build Coastguard Worker    """ Version interface for Jython.
469*cda5da8dSAndroid Build Coastguard Worker
470*cda5da8dSAndroid Build Coastguard Worker        Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
471*cda5da8dSAndroid Build Coastguard Worker        a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
472*cda5da8dSAndroid Build Coastguard Worker        tuple (os_name, os_version, os_arch).
473*cda5da8dSAndroid Build Coastguard Worker
474*cda5da8dSAndroid Build Coastguard Worker        Values which cannot be determined are set to the defaults
475*cda5da8dSAndroid Build Coastguard Worker        given as parameters (which all default to '').
476*cda5da8dSAndroid Build Coastguard Worker
477*cda5da8dSAndroid Build Coastguard Worker    """
478*cda5da8dSAndroid Build Coastguard Worker    # Import the needed APIs
479*cda5da8dSAndroid Build Coastguard Worker    try:
480*cda5da8dSAndroid Build Coastguard Worker        import java.lang
481*cda5da8dSAndroid Build Coastguard Worker    except ImportError:
482*cda5da8dSAndroid Build Coastguard Worker        return release, vendor, vminfo, osinfo
483*cda5da8dSAndroid Build Coastguard Worker
484*cda5da8dSAndroid Build Coastguard Worker    vendor = _java_getprop('java.vendor', vendor)
485*cda5da8dSAndroid Build Coastguard Worker    release = _java_getprop('java.version', release)
486*cda5da8dSAndroid Build Coastguard Worker    vm_name, vm_release, vm_vendor = vminfo
487*cda5da8dSAndroid Build Coastguard Worker    vm_name = _java_getprop('java.vm.name', vm_name)
488*cda5da8dSAndroid Build Coastguard Worker    vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
489*cda5da8dSAndroid Build Coastguard Worker    vm_release = _java_getprop('java.vm.version', vm_release)
490*cda5da8dSAndroid Build Coastguard Worker    vminfo = vm_name, vm_release, vm_vendor
491*cda5da8dSAndroid Build Coastguard Worker    os_name, os_version, os_arch = osinfo
492*cda5da8dSAndroid Build Coastguard Worker    os_arch = _java_getprop('java.os.arch', os_arch)
493*cda5da8dSAndroid Build Coastguard Worker    os_name = _java_getprop('java.os.name', os_name)
494*cda5da8dSAndroid Build Coastguard Worker    os_version = _java_getprop('java.os.version', os_version)
495*cda5da8dSAndroid Build Coastguard Worker    osinfo = os_name, os_version, os_arch
496*cda5da8dSAndroid Build Coastguard Worker
497*cda5da8dSAndroid Build Coastguard Worker    return release, vendor, vminfo, osinfo
498*cda5da8dSAndroid Build Coastguard Worker
499*cda5da8dSAndroid Build Coastguard Worker### System name aliasing
500*cda5da8dSAndroid Build Coastguard Worker
501*cda5da8dSAndroid Build Coastguard Workerdef system_alias(system, release, version):
502*cda5da8dSAndroid Build Coastguard Worker
503*cda5da8dSAndroid Build Coastguard Worker    """ Returns (system, release, version) aliased to common
504*cda5da8dSAndroid Build Coastguard Worker        marketing names used for some systems.
505*cda5da8dSAndroid Build Coastguard Worker
506*cda5da8dSAndroid Build Coastguard Worker        It also does some reordering of the information in some cases
507*cda5da8dSAndroid Build Coastguard Worker        where it would otherwise cause confusion.
508*cda5da8dSAndroid Build Coastguard Worker
509*cda5da8dSAndroid Build Coastguard Worker    """
510*cda5da8dSAndroid Build Coastguard Worker    if system == 'SunOS':
511*cda5da8dSAndroid Build Coastguard Worker        # Sun's OS
512*cda5da8dSAndroid Build Coastguard Worker        if release < '5':
513*cda5da8dSAndroid Build Coastguard Worker            # These releases use the old name SunOS
514*cda5da8dSAndroid Build Coastguard Worker            return system, release, version
515*cda5da8dSAndroid Build Coastguard Worker        # Modify release (marketing release = SunOS release - 3)
516*cda5da8dSAndroid Build Coastguard Worker        l = release.split('.')
517*cda5da8dSAndroid Build Coastguard Worker        if l:
518*cda5da8dSAndroid Build Coastguard Worker            try:
519*cda5da8dSAndroid Build Coastguard Worker                major = int(l[0])
520*cda5da8dSAndroid Build Coastguard Worker            except ValueError:
521*cda5da8dSAndroid Build Coastguard Worker                pass
522*cda5da8dSAndroid Build Coastguard Worker            else:
523*cda5da8dSAndroid Build Coastguard Worker                major = major - 3
524*cda5da8dSAndroid Build Coastguard Worker                l[0] = str(major)
525*cda5da8dSAndroid Build Coastguard Worker                release = '.'.join(l)
526*cda5da8dSAndroid Build Coastguard Worker        if release < '6':
527*cda5da8dSAndroid Build Coastguard Worker            system = 'Solaris'
528*cda5da8dSAndroid Build Coastguard Worker        else:
529*cda5da8dSAndroid Build Coastguard Worker            # XXX Whatever the new SunOS marketing name is...
530*cda5da8dSAndroid Build Coastguard Worker            system = 'Solaris'
531*cda5da8dSAndroid Build Coastguard Worker
532*cda5da8dSAndroid Build Coastguard Worker    elif system in ('win32', 'win16'):
533*cda5da8dSAndroid Build Coastguard Worker        # In case one of the other tricks
534*cda5da8dSAndroid Build Coastguard Worker        system = 'Windows'
535*cda5da8dSAndroid Build Coastguard Worker
536*cda5da8dSAndroid Build Coastguard Worker    # bpo-35516: Don't replace Darwin with macOS since input release and
537*cda5da8dSAndroid Build Coastguard Worker    # version arguments can be different than the currently running version.
538*cda5da8dSAndroid Build Coastguard Worker
539*cda5da8dSAndroid Build Coastguard Worker    return system, release, version
540*cda5da8dSAndroid Build Coastguard Worker
541*cda5da8dSAndroid Build Coastguard Worker### Various internal helpers
542*cda5da8dSAndroid Build Coastguard Worker
543*cda5da8dSAndroid Build Coastguard Workerdef _platform(*args):
544*cda5da8dSAndroid Build Coastguard Worker
545*cda5da8dSAndroid Build Coastguard Worker    """ Helper to format the platform string in a filename
546*cda5da8dSAndroid Build Coastguard Worker        compatible format e.g. "system-version-machine".
547*cda5da8dSAndroid Build Coastguard Worker    """
548*cda5da8dSAndroid Build Coastguard Worker    # Format the platform string
549*cda5da8dSAndroid Build Coastguard Worker    platform = '-'.join(x.strip() for x in filter(len, args))
550*cda5da8dSAndroid Build Coastguard Worker
551*cda5da8dSAndroid Build Coastguard Worker    # Cleanup some possible filename obstacles...
552*cda5da8dSAndroid Build Coastguard Worker    platform = platform.replace(' ', '_')
553*cda5da8dSAndroid Build Coastguard Worker    platform = platform.replace('/', '-')
554*cda5da8dSAndroid Build Coastguard Worker    platform = platform.replace('\\', '-')
555*cda5da8dSAndroid Build Coastguard Worker    platform = platform.replace(':', '-')
556*cda5da8dSAndroid Build Coastguard Worker    platform = platform.replace(';', '-')
557*cda5da8dSAndroid Build Coastguard Worker    platform = platform.replace('"', '-')
558*cda5da8dSAndroid Build Coastguard Worker    platform = platform.replace('(', '-')
559*cda5da8dSAndroid Build Coastguard Worker    platform = platform.replace(')', '-')
560*cda5da8dSAndroid Build Coastguard Worker
561*cda5da8dSAndroid Build Coastguard Worker    # No need to report 'unknown' information...
562*cda5da8dSAndroid Build Coastguard Worker    platform = platform.replace('unknown', '')
563*cda5da8dSAndroid Build Coastguard Worker
564*cda5da8dSAndroid Build Coastguard Worker    # Fold '--'s and remove trailing '-'
565*cda5da8dSAndroid Build Coastguard Worker    while 1:
566*cda5da8dSAndroid Build Coastguard Worker        cleaned = platform.replace('--', '-')
567*cda5da8dSAndroid Build Coastguard Worker        if cleaned == platform:
568*cda5da8dSAndroid Build Coastguard Worker            break
569*cda5da8dSAndroid Build Coastguard Worker        platform = cleaned
570*cda5da8dSAndroid Build Coastguard Worker    while platform[-1] == '-':
571*cda5da8dSAndroid Build Coastguard Worker        platform = platform[:-1]
572*cda5da8dSAndroid Build Coastguard Worker
573*cda5da8dSAndroid Build Coastguard Worker    return platform
574*cda5da8dSAndroid Build Coastguard Worker
575*cda5da8dSAndroid Build Coastguard Workerdef _node(default=''):
576*cda5da8dSAndroid Build Coastguard Worker
577*cda5da8dSAndroid Build Coastguard Worker    """ Helper to determine the node name of this machine.
578*cda5da8dSAndroid Build Coastguard Worker    """
579*cda5da8dSAndroid Build Coastguard Worker    try:
580*cda5da8dSAndroid Build Coastguard Worker        import socket
581*cda5da8dSAndroid Build Coastguard Worker    except ImportError:
582*cda5da8dSAndroid Build Coastguard Worker        # No sockets...
583*cda5da8dSAndroid Build Coastguard Worker        return default
584*cda5da8dSAndroid Build Coastguard Worker    try:
585*cda5da8dSAndroid Build Coastguard Worker        return socket.gethostname()
586*cda5da8dSAndroid Build Coastguard Worker    except OSError:
587*cda5da8dSAndroid Build Coastguard Worker        # Still not working...
588*cda5da8dSAndroid Build Coastguard Worker        return default
589*cda5da8dSAndroid Build Coastguard Worker
590*cda5da8dSAndroid Build Coastguard Workerdef _follow_symlinks(filepath):
591*cda5da8dSAndroid Build Coastguard Worker
592*cda5da8dSAndroid Build Coastguard Worker    """ In case filepath is a symlink, follow it until a
593*cda5da8dSAndroid Build Coastguard Worker        real file is reached.
594*cda5da8dSAndroid Build Coastguard Worker    """
595*cda5da8dSAndroid Build Coastguard Worker    filepath = os.path.abspath(filepath)
596*cda5da8dSAndroid Build Coastguard Worker    while os.path.islink(filepath):
597*cda5da8dSAndroid Build Coastguard Worker        filepath = os.path.normpath(
598*cda5da8dSAndroid Build Coastguard Worker            os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
599*cda5da8dSAndroid Build Coastguard Worker    return filepath
600*cda5da8dSAndroid Build Coastguard Worker
601*cda5da8dSAndroid Build Coastguard Worker
602*cda5da8dSAndroid Build Coastguard Workerdef _syscmd_file(target, default=''):
603*cda5da8dSAndroid Build Coastguard Worker
604*cda5da8dSAndroid Build Coastguard Worker    """ Interface to the system's file command.
605*cda5da8dSAndroid Build Coastguard Worker
606*cda5da8dSAndroid Build Coastguard Worker        The function uses the -b option of the file command to have it
607*cda5da8dSAndroid Build Coastguard Worker        omit the filename in its output. Follow the symlinks. It returns
608*cda5da8dSAndroid Build Coastguard Worker        default in case the command should fail.
609*cda5da8dSAndroid Build Coastguard Worker
610*cda5da8dSAndroid Build Coastguard Worker    """
611*cda5da8dSAndroid Build Coastguard Worker    if sys.platform in ('dos', 'win32', 'win16'):
612*cda5da8dSAndroid Build Coastguard Worker        # XXX Others too ?
613*cda5da8dSAndroid Build Coastguard Worker        return default
614*cda5da8dSAndroid Build Coastguard Worker
615*cda5da8dSAndroid Build Coastguard Worker    try:
616*cda5da8dSAndroid Build Coastguard Worker        import subprocess
617*cda5da8dSAndroid Build Coastguard Worker    except ImportError:
618*cda5da8dSAndroid Build Coastguard Worker        return default
619*cda5da8dSAndroid Build Coastguard Worker    target = _follow_symlinks(target)
620*cda5da8dSAndroid Build Coastguard Worker    # "file" output is locale dependent: force the usage of the C locale
621*cda5da8dSAndroid Build Coastguard Worker    # to get deterministic behavior.
622*cda5da8dSAndroid Build Coastguard Worker    env = dict(os.environ, LC_ALL='C')
623*cda5da8dSAndroid Build Coastguard Worker    try:
624*cda5da8dSAndroid Build Coastguard Worker        # -b: do not prepend filenames to output lines (brief mode)
625*cda5da8dSAndroid Build Coastguard Worker        output = subprocess.check_output(['file', '-b', target],
626*cda5da8dSAndroid Build Coastguard Worker                                         stderr=subprocess.DEVNULL,
627*cda5da8dSAndroid Build Coastguard Worker                                         env=env)
628*cda5da8dSAndroid Build Coastguard Worker    except (OSError, subprocess.CalledProcessError):
629*cda5da8dSAndroid Build Coastguard Worker        return default
630*cda5da8dSAndroid Build Coastguard Worker    if not output:
631*cda5da8dSAndroid Build Coastguard Worker        return default
632*cda5da8dSAndroid Build Coastguard Worker    # With the C locale, the output should be mostly ASCII-compatible.
633*cda5da8dSAndroid Build Coastguard Worker    # Decode from Latin-1 to prevent Unicode decode error.
634*cda5da8dSAndroid Build Coastguard Worker    return output.decode('latin-1')
635*cda5da8dSAndroid Build Coastguard Worker
636*cda5da8dSAndroid Build Coastguard Worker### Information about the used architecture
637*cda5da8dSAndroid Build Coastguard Worker
638*cda5da8dSAndroid Build Coastguard Worker# Default values for architecture; non-empty strings override the
639*cda5da8dSAndroid Build Coastguard Worker# defaults given as parameters
640*cda5da8dSAndroid Build Coastguard Worker_default_architecture = {
641*cda5da8dSAndroid Build Coastguard Worker    'win32': ('', 'WindowsPE'),
642*cda5da8dSAndroid Build Coastguard Worker    'win16': ('', 'Windows'),
643*cda5da8dSAndroid Build Coastguard Worker    'dos': ('', 'MSDOS'),
644*cda5da8dSAndroid Build Coastguard Worker}
645*cda5da8dSAndroid Build Coastguard Worker
646*cda5da8dSAndroid Build Coastguard Workerdef architecture(executable=sys.executable, bits='', linkage=''):
647*cda5da8dSAndroid Build Coastguard Worker
648*cda5da8dSAndroid Build Coastguard Worker    """ Queries the given executable (defaults to the Python interpreter
649*cda5da8dSAndroid Build Coastguard Worker        binary) for various architecture information.
650*cda5da8dSAndroid Build Coastguard Worker
651*cda5da8dSAndroid Build Coastguard Worker        Returns a tuple (bits, linkage) which contains information about
652*cda5da8dSAndroid Build Coastguard Worker        the bit architecture and the linkage format used for the
653*cda5da8dSAndroid Build Coastguard Worker        executable. Both values are returned as strings.
654*cda5da8dSAndroid Build Coastguard Worker
655*cda5da8dSAndroid Build Coastguard Worker        Values that cannot be determined are returned as given by the
656*cda5da8dSAndroid Build Coastguard Worker        parameter presets. If bits is given as '', the sizeof(pointer)
657*cda5da8dSAndroid Build Coastguard Worker        (or sizeof(long) on Python version < 1.5.2) is used as
658*cda5da8dSAndroid Build Coastguard Worker        indicator for the supported pointer size.
659*cda5da8dSAndroid Build Coastguard Worker
660*cda5da8dSAndroid Build Coastguard Worker        The function relies on the system's "file" command to do the
661*cda5da8dSAndroid Build Coastguard Worker        actual work. This is available on most if not all Unix
662*cda5da8dSAndroid Build Coastguard Worker        platforms. On some non-Unix platforms where the "file" command
663*cda5da8dSAndroid Build Coastguard Worker        does not exist and the executable is set to the Python interpreter
664*cda5da8dSAndroid Build Coastguard Worker        binary defaults from _default_architecture are used.
665*cda5da8dSAndroid Build Coastguard Worker
666*cda5da8dSAndroid Build Coastguard Worker    """
667*cda5da8dSAndroid Build Coastguard Worker    # Use the sizeof(pointer) as default number of bits if nothing
668*cda5da8dSAndroid Build Coastguard Worker    # else is given as default.
669*cda5da8dSAndroid Build Coastguard Worker    if not bits:
670*cda5da8dSAndroid Build Coastguard Worker        import struct
671*cda5da8dSAndroid Build Coastguard Worker        size = struct.calcsize('P')
672*cda5da8dSAndroid Build Coastguard Worker        bits = str(size * 8) + 'bit'
673*cda5da8dSAndroid Build Coastguard Worker
674*cda5da8dSAndroid Build Coastguard Worker    # Get data from the 'file' system command
675*cda5da8dSAndroid Build Coastguard Worker    if executable:
676*cda5da8dSAndroid Build Coastguard Worker        fileout = _syscmd_file(executable, '')
677*cda5da8dSAndroid Build Coastguard Worker    else:
678*cda5da8dSAndroid Build Coastguard Worker        fileout = ''
679*cda5da8dSAndroid Build Coastguard Worker
680*cda5da8dSAndroid Build Coastguard Worker    if not fileout and \
681*cda5da8dSAndroid Build Coastguard Worker       executable == sys.executable:
682*cda5da8dSAndroid Build Coastguard Worker        # "file" command did not return anything; we'll try to provide
683*cda5da8dSAndroid Build Coastguard Worker        # some sensible defaults then...
684*cda5da8dSAndroid Build Coastguard Worker        if sys.platform in _default_architecture:
685*cda5da8dSAndroid Build Coastguard Worker            b, l = _default_architecture[sys.platform]
686*cda5da8dSAndroid Build Coastguard Worker            if b:
687*cda5da8dSAndroid Build Coastguard Worker                bits = b
688*cda5da8dSAndroid Build Coastguard Worker            if l:
689*cda5da8dSAndroid Build Coastguard Worker                linkage = l
690*cda5da8dSAndroid Build Coastguard Worker        return bits, linkage
691*cda5da8dSAndroid Build Coastguard Worker
692*cda5da8dSAndroid Build Coastguard Worker    if 'executable' not in fileout and 'shared object' not in fileout:
693*cda5da8dSAndroid Build Coastguard Worker        # Format not supported
694*cda5da8dSAndroid Build Coastguard Worker        return bits, linkage
695*cda5da8dSAndroid Build Coastguard Worker
696*cda5da8dSAndroid Build Coastguard Worker    # Bits
697*cda5da8dSAndroid Build Coastguard Worker    if '32-bit' in fileout:
698*cda5da8dSAndroid Build Coastguard Worker        bits = '32bit'
699*cda5da8dSAndroid Build Coastguard Worker    elif '64-bit' in fileout:
700*cda5da8dSAndroid Build Coastguard Worker        bits = '64bit'
701*cda5da8dSAndroid Build Coastguard Worker
702*cda5da8dSAndroid Build Coastguard Worker    # Linkage
703*cda5da8dSAndroid Build Coastguard Worker    if 'ELF' in fileout:
704*cda5da8dSAndroid Build Coastguard Worker        linkage = 'ELF'
705*cda5da8dSAndroid Build Coastguard Worker    elif 'PE' in fileout:
706*cda5da8dSAndroid Build Coastguard Worker        # E.g. Windows uses this format
707*cda5da8dSAndroid Build Coastguard Worker        if 'Windows' in fileout:
708*cda5da8dSAndroid Build Coastguard Worker            linkage = 'WindowsPE'
709*cda5da8dSAndroid Build Coastguard Worker        else:
710*cda5da8dSAndroid Build Coastguard Worker            linkage = 'PE'
711*cda5da8dSAndroid Build Coastguard Worker    elif 'COFF' in fileout:
712*cda5da8dSAndroid Build Coastguard Worker        linkage = 'COFF'
713*cda5da8dSAndroid Build Coastguard Worker    elif 'MS-DOS' in fileout:
714*cda5da8dSAndroid Build Coastguard Worker        linkage = 'MSDOS'
715*cda5da8dSAndroid Build Coastguard Worker    else:
716*cda5da8dSAndroid Build Coastguard Worker        # XXX the A.OUT format also falls under this class...
717*cda5da8dSAndroid Build Coastguard Worker        pass
718*cda5da8dSAndroid Build Coastguard Worker
719*cda5da8dSAndroid Build Coastguard Worker    return bits, linkage
720*cda5da8dSAndroid Build Coastguard Worker
721*cda5da8dSAndroid Build Coastguard Worker
722*cda5da8dSAndroid Build Coastguard Workerdef _get_machine_win32():
723*cda5da8dSAndroid Build Coastguard Worker    # Try to use the PROCESSOR_* environment variables
724*cda5da8dSAndroid Build Coastguard Worker    # available on Win XP and later; see
725*cda5da8dSAndroid Build Coastguard Worker    # http://support.microsoft.com/kb/888731 and
726*cda5da8dSAndroid Build Coastguard Worker    # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
727*cda5da8dSAndroid Build Coastguard Worker
728*cda5da8dSAndroid Build Coastguard Worker    # WOW64 processes mask the native architecture
729*cda5da8dSAndroid Build Coastguard Worker    return (
730*cda5da8dSAndroid Build Coastguard Worker        os.environ.get('PROCESSOR_ARCHITEW6432', '') or
731*cda5da8dSAndroid Build Coastguard Worker        os.environ.get('PROCESSOR_ARCHITECTURE', '')
732*cda5da8dSAndroid Build Coastguard Worker    )
733*cda5da8dSAndroid Build Coastguard Worker
734*cda5da8dSAndroid Build Coastguard Worker
735*cda5da8dSAndroid Build Coastguard Workerclass _Processor:
736*cda5da8dSAndroid Build Coastguard Worker    @classmethod
737*cda5da8dSAndroid Build Coastguard Worker    def get(cls):
738*cda5da8dSAndroid Build Coastguard Worker        func = getattr(cls, f'get_{sys.platform}', cls.from_subprocess)
739*cda5da8dSAndroid Build Coastguard Worker        return func() or ''
740*cda5da8dSAndroid Build Coastguard Worker
741*cda5da8dSAndroid Build Coastguard Worker    def get_win32():
742*cda5da8dSAndroid Build Coastguard Worker        return os.environ.get('PROCESSOR_IDENTIFIER', _get_machine_win32())
743*cda5da8dSAndroid Build Coastguard Worker
744*cda5da8dSAndroid Build Coastguard Worker    def get_OpenVMS():
745*cda5da8dSAndroid Build Coastguard Worker        try:
746*cda5da8dSAndroid Build Coastguard Worker            import vms_lib
747*cda5da8dSAndroid Build Coastguard Worker        except ImportError:
748*cda5da8dSAndroid Build Coastguard Worker            pass
749*cda5da8dSAndroid Build Coastguard Worker        else:
750*cda5da8dSAndroid Build Coastguard Worker            csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
751*cda5da8dSAndroid Build Coastguard Worker            return 'Alpha' if cpu_number >= 128 else 'VAX'
752*cda5da8dSAndroid Build Coastguard Worker
753*cda5da8dSAndroid Build Coastguard Worker    def from_subprocess():
754*cda5da8dSAndroid Build Coastguard Worker        """
755*cda5da8dSAndroid Build Coastguard Worker        Fall back to `uname -p`
756*cda5da8dSAndroid Build Coastguard Worker        """
757*cda5da8dSAndroid Build Coastguard Worker        try:
758*cda5da8dSAndroid Build Coastguard Worker            import subprocess
759*cda5da8dSAndroid Build Coastguard Worker        except ImportError:
760*cda5da8dSAndroid Build Coastguard Worker            return None
761*cda5da8dSAndroid Build Coastguard Worker        try:
762*cda5da8dSAndroid Build Coastguard Worker            return subprocess.check_output(
763*cda5da8dSAndroid Build Coastguard Worker                ['uname', '-p'],
764*cda5da8dSAndroid Build Coastguard Worker                stderr=subprocess.DEVNULL,
765*cda5da8dSAndroid Build Coastguard Worker                text=True,
766*cda5da8dSAndroid Build Coastguard Worker                encoding="utf8",
767*cda5da8dSAndroid Build Coastguard Worker            ).strip()
768*cda5da8dSAndroid Build Coastguard Worker        except (OSError, subprocess.CalledProcessError):
769*cda5da8dSAndroid Build Coastguard Worker            pass
770*cda5da8dSAndroid Build Coastguard Worker
771*cda5da8dSAndroid Build Coastguard Worker
772*cda5da8dSAndroid Build Coastguard Workerdef _unknown_as_blank(val):
773*cda5da8dSAndroid Build Coastguard Worker    return '' if val == 'unknown' else val
774*cda5da8dSAndroid Build Coastguard Worker
775*cda5da8dSAndroid Build Coastguard Worker
776*cda5da8dSAndroid Build Coastguard Worker### Portable uname() interface
777*cda5da8dSAndroid Build Coastguard Worker
778*cda5da8dSAndroid Build Coastguard Workerclass uname_result(
779*cda5da8dSAndroid Build Coastguard Worker    collections.namedtuple(
780*cda5da8dSAndroid Build Coastguard Worker        "uname_result_base",
781*cda5da8dSAndroid Build Coastguard Worker        "system node release version machine")
782*cda5da8dSAndroid Build Coastguard Worker        ):
783*cda5da8dSAndroid Build Coastguard Worker    """
784*cda5da8dSAndroid Build Coastguard Worker    A uname_result that's largely compatible with a
785*cda5da8dSAndroid Build Coastguard Worker    simple namedtuple except that 'processor' is
786*cda5da8dSAndroid Build Coastguard Worker    resolved late and cached to avoid calling "uname"
787*cda5da8dSAndroid Build Coastguard Worker    except when needed.
788*cda5da8dSAndroid Build Coastguard Worker    """
789*cda5da8dSAndroid Build Coastguard Worker
790*cda5da8dSAndroid Build Coastguard Worker    _fields = ('system', 'node', 'release', 'version', 'machine', 'processor')
791*cda5da8dSAndroid Build Coastguard Worker
792*cda5da8dSAndroid Build Coastguard Worker    @functools.cached_property
793*cda5da8dSAndroid Build Coastguard Worker    def processor(self):
794*cda5da8dSAndroid Build Coastguard Worker        return _unknown_as_blank(_Processor.get())
795*cda5da8dSAndroid Build Coastguard Worker
796*cda5da8dSAndroid Build Coastguard Worker    def __iter__(self):
797*cda5da8dSAndroid Build Coastguard Worker        return itertools.chain(
798*cda5da8dSAndroid Build Coastguard Worker            super().__iter__(),
799*cda5da8dSAndroid Build Coastguard Worker            (self.processor,)
800*cda5da8dSAndroid Build Coastguard Worker        )
801*cda5da8dSAndroid Build Coastguard Worker
802*cda5da8dSAndroid Build Coastguard Worker    @classmethod
803*cda5da8dSAndroid Build Coastguard Worker    def _make(cls, iterable):
804*cda5da8dSAndroid Build Coastguard Worker        # override factory to affect length check
805*cda5da8dSAndroid Build Coastguard Worker        num_fields = len(cls._fields) - 1
806*cda5da8dSAndroid Build Coastguard Worker        result = cls.__new__(cls, *iterable)
807*cda5da8dSAndroid Build Coastguard Worker        if len(result) != num_fields + 1:
808*cda5da8dSAndroid Build Coastguard Worker            msg = f'Expected {num_fields} arguments, got {len(result)}'
809*cda5da8dSAndroid Build Coastguard Worker            raise TypeError(msg)
810*cda5da8dSAndroid Build Coastguard Worker        return result
811*cda5da8dSAndroid Build Coastguard Worker
812*cda5da8dSAndroid Build Coastguard Worker    def __getitem__(self, key):
813*cda5da8dSAndroid Build Coastguard Worker        return tuple(self)[key]
814*cda5da8dSAndroid Build Coastguard Worker
815*cda5da8dSAndroid Build Coastguard Worker    def __len__(self):
816*cda5da8dSAndroid Build Coastguard Worker        return len(tuple(iter(self)))
817*cda5da8dSAndroid Build Coastguard Worker
818*cda5da8dSAndroid Build Coastguard Worker    def __reduce__(self):
819*cda5da8dSAndroid Build Coastguard Worker        return uname_result, tuple(self)[:len(self._fields) - 1]
820*cda5da8dSAndroid Build Coastguard Worker
821*cda5da8dSAndroid Build Coastguard Worker
822*cda5da8dSAndroid Build Coastguard Worker_uname_cache = None
823*cda5da8dSAndroid Build Coastguard Worker
824*cda5da8dSAndroid Build Coastguard Worker
825*cda5da8dSAndroid Build Coastguard Workerdef uname():
826*cda5da8dSAndroid Build Coastguard Worker
827*cda5da8dSAndroid Build Coastguard Worker    """ Fairly portable uname interface. Returns a tuple
828*cda5da8dSAndroid Build Coastguard Worker        of strings (system, node, release, version, machine, processor)
829*cda5da8dSAndroid Build Coastguard Worker        identifying the underlying platform.
830*cda5da8dSAndroid Build Coastguard Worker
831*cda5da8dSAndroid Build Coastguard Worker        Note that unlike the os.uname function this also returns
832*cda5da8dSAndroid Build Coastguard Worker        possible processor information as an additional tuple entry.
833*cda5da8dSAndroid Build Coastguard Worker
834*cda5da8dSAndroid Build Coastguard Worker        Entries which cannot be determined are set to ''.
835*cda5da8dSAndroid Build Coastguard Worker
836*cda5da8dSAndroid Build Coastguard Worker    """
837*cda5da8dSAndroid Build Coastguard Worker    global _uname_cache
838*cda5da8dSAndroid Build Coastguard Worker
839*cda5da8dSAndroid Build Coastguard Worker    if _uname_cache is not None:
840*cda5da8dSAndroid Build Coastguard Worker        return _uname_cache
841*cda5da8dSAndroid Build Coastguard Worker
842*cda5da8dSAndroid Build Coastguard Worker    # Get some infos from the builtin os.uname API...
843*cda5da8dSAndroid Build Coastguard Worker    try:
844*cda5da8dSAndroid Build Coastguard Worker        system, node, release, version, machine = infos = os.uname()
845*cda5da8dSAndroid Build Coastguard Worker    except AttributeError:
846*cda5da8dSAndroid Build Coastguard Worker        system = sys.platform
847*cda5da8dSAndroid Build Coastguard Worker        node = _node()
848*cda5da8dSAndroid Build Coastguard Worker        release = version = machine = ''
849*cda5da8dSAndroid Build Coastguard Worker        infos = ()
850*cda5da8dSAndroid Build Coastguard Worker
851*cda5da8dSAndroid Build Coastguard Worker    if not any(infos):
852*cda5da8dSAndroid Build Coastguard Worker        # uname is not available
853*cda5da8dSAndroid Build Coastguard Worker
854*cda5da8dSAndroid Build Coastguard Worker        # Try win32_ver() on win32 platforms
855*cda5da8dSAndroid Build Coastguard Worker        if system == 'win32':
856*cda5da8dSAndroid Build Coastguard Worker            release, version, csd, ptype = win32_ver()
857*cda5da8dSAndroid Build Coastguard Worker            machine = machine or _get_machine_win32()
858*cda5da8dSAndroid Build Coastguard Worker
859*cda5da8dSAndroid Build Coastguard Worker        # Try the 'ver' system command available on some
860*cda5da8dSAndroid Build Coastguard Worker        # platforms
861*cda5da8dSAndroid Build Coastguard Worker        if not (release and version):
862*cda5da8dSAndroid Build Coastguard Worker            system, release, version = _syscmd_ver(system)
863*cda5da8dSAndroid Build Coastguard Worker            # Normalize system to what win32_ver() normally returns
864*cda5da8dSAndroid Build Coastguard Worker            # (_syscmd_ver() tends to return the vendor name as well)
865*cda5da8dSAndroid Build Coastguard Worker            if system == 'Microsoft Windows':
866*cda5da8dSAndroid Build Coastguard Worker                system = 'Windows'
867*cda5da8dSAndroid Build Coastguard Worker            elif system == 'Microsoft' and release == 'Windows':
868*cda5da8dSAndroid Build Coastguard Worker                # Under Windows Vista and Windows Server 2008,
869*cda5da8dSAndroid Build Coastguard Worker                # Microsoft changed the output of the ver command. The
870*cda5da8dSAndroid Build Coastguard Worker                # release is no longer printed.  This causes the
871*cda5da8dSAndroid Build Coastguard Worker                # system and release to be misidentified.
872*cda5da8dSAndroid Build Coastguard Worker                system = 'Windows'
873*cda5da8dSAndroid Build Coastguard Worker                if '6.0' == version[:3]:
874*cda5da8dSAndroid Build Coastguard Worker                    release = 'Vista'
875*cda5da8dSAndroid Build Coastguard Worker                else:
876*cda5da8dSAndroid Build Coastguard Worker                    release = ''
877*cda5da8dSAndroid Build Coastguard Worker
878*cda5da8dSAndroid Build Coastguard Worker        # In case we still don't know anything useful, we'll try to
879*cda5da8dSAndroid Build Coastguard Worker        # help ourselves
880*cda5da8dSAndroid Build Coastguard Worker        if system in ('win32', 'win16'):
881*cda5da8dSAndroid Build Coastguard Worker            if not version:
882*cda5da8dSAndroid Build Coastguard Worker                if system == 'win32':
883*cda5da8dSAndroid Build Coastguard Worker                    version = '32bit'
884*cda5da8dSAndroid Build Coastguard Worker                else:
885*cda5da8dSAndroid Build Coastguard Worker                    version = '16bit'
886*cda5da8dSAndroid Build Coastguard Worker            system = 'Windows'
887*cda5da8dSAndroid Build Coastguard Worker
888*cda5da8dSAndroid Build Coastguard Worker        elif system[:4] == 'java':
889*cda5da8dSAndroid Build Coastguard Worker            release, vendor, vminfo, osinfo = java_ver()
890*cda5da8dSAndroid Build Coastguard Worker            system = 'Java'
891*cda5da8dSAndroid Build Coastguard Worker            version = ', '.join(vminfo)
892*cda5da8dSAndroid Build Coastguard Worker            if not version:
893*cda5da8dSAndroid Build Coastguard Worker                version = vendor
894*cda5da8dSAndroid Build Coastguard Worker
895*cda5da8dSAndroid Build Coastguard Worker    # System specific extensions
896*cda5da8dSAndroid Build Coastguard Worker    if system == 'OpenVMS':
897*cda5da8dSAndroid Build Coastguard Worker        # OpenVMS seems to have release and version mixed up
898*cda5da8dSAndroid Build Coastguard Worker        if not release or release == '0':
899*cda5da8dSAndroid Build Coastguard Worker            release = version
900*cda5da8dSAndroid Build Coastguard Worker            version = ''
901*cda5da8dSAndroid Build Coastguard Worker
902*cda5da8dSAndroid Build Coastguard Worker    #  normalize name
903*cda5da8dSAndroid Build Coastguard Worker    if system == 'Microsoft' and release == 'Windows':
904*cda5da8dSAndroid Build Coastguard Worker        system = 'Windows'
905*cda5da8dSAndroid Build Coastguard Worker        release = 'Vista'
906*cda5da8dSAndroid Build Coastguard Worker
907*cda5da8dSAndroid Build Coastguard Worker    vals = system, node, release, version, machine
908*cda5da8dSAndroid Build Coastguard Worker    # Replace 'unknown' values with the more portable ''
909*cda5da8dSAndroid Build Coastguard Worker    _uname_cache = uname_result(*map(_unknown_as_blank, vals))
910*cda5da8dSAndroid Build Coastguard Worker    return _uname_cache
911*cda5da8dSAndroid Build Coastguard Worker
912*cda5da8dSAndroid Build Coastguard Worker### Direct interfaces to some of the uname() return values
913*cda5da8dSAndroid Build Coastguard Worker
914*cda5da8dSAndroid Build Coastguard Workerdef system():
915*cda5da8dSAndroid Build Coastguard Worker
916*cda5da8dSAndroid Build Coastguard Worker    """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
917*cda5da8dSAndroid Build Coastguard Worker
918*cda5da8dSAndroid Build Coastguard Worker        An empty string is returned if the value cannot be determined.
919*cda5da8dSAndroid Build Coastguard Worker
920*cda5da8dSAndroid Build Coastguard Worker    """
921*cda5da8dSAndroid Build Coastguard Worker    return uname().system
922*cda5da8dSAndroid Build Coastguard Worker
923*cda5da8dSAndroid Build Coastguard Workerdef node():
924*cda5da8dSAndroid Build Coastguard Worker
925*cda5da8dSAndroid Build Coastguard Worker    """ Returns the computer's network name (which may not be fully
926*cda5da8dSAndroid Build Coastguard Worker        qualified)
927*cda5da8dSAndroid Build Coastguard Worker
928*cda5da8dSAndroid Build Coastguard Worker        An empty string is returned if the value cannot be determined.
929*cda5da8dSAndroid Build Coastguard Worker
930*cda5da8dSAndroid Build Coastguard Worker    """
931*cda5da8dSAndroid Build Coastguard Worker    return uname().node
932*cda5da8dSAndroid Build Coastguard Worker
933*cda5da8dSAndroid Build Coastguard Workerdef release():
934*cda5da8dSAndroid Build Coastguard Worker
935*cda5da8dSAndroid Build Coastguard Worker    """ Returns the system's release, e.g. '2.2.0' or 'NT'
936*cda5da8dSAndroid Build Coastguard Worker
937*cda5da8dSAndroid Build Coastguard Worker        An empty string is returned if the value cannot be determined.
938*cda5da8dSAndroid Build Coastguard Worker
939*cda5da8dSAndroid Build Coastguard Worker    """
940*cda5da8dSAndroid Build Coastguard Worker    return uname().release
941*cda5da8dSAndroid Build Coastguard Worker
942*cda5da8dSAndroid Build Coastguard Workerdef version():
943*cda5da8dSAndroid Build Coastguard Worker
944*cda5da8dSAndroid Build Coastguard Worker    """ Returns the system's release version, e.g. '#3 on degas'
945*cda5da8dSAndroid Build Coastguard Worker
946*cda5da8dSAndroid Build Coastguard Worker        An empty string is returned if the value cannot be determined.
947*cda5da8dSAndroid Build Coastguard Worker
948*cda5da8dSAndroid Build Coastguard Worker    """
949*cda5da8dSAndroid Build Coastguard Worker    return uname().version
950*cda5da8dSAndroid Build Coastguard Worker
951*cda5da8dSAndroid Build Coastguard Workerdef machine():
952*cda5da8dSAndroid Build Coastguard Worker
953*cda5da8dSAndroid Build Coastguard Worker    """ Returns the machine type, e.g. 'i386'
954*cda5da8dSAndroid Build Coastguard Worker
955*cda5da8dSAndroid Build Coastguard Worker        An empty string is returned if the value cannot be determined.
956*cda5da8dSAndroid Build Coastguard Worker
957*cda5da8dSAndroid Build Coastguard Worker    """
958*cda5da8dSAndroid Build Coastguard Worker    return uname().machine
959*cda5da8dSAndroid Build Coastguard Worker
960*cda5da8dSAndroid Build Coastguard Workerdef processor():
961*cda5da8dSAndroid Build Coastguard Worker
962*cda5da8dSAndroid Build Coastguard Worker    """ Returns the (true) processor name, e.g. 'amdk6'
963*cda5da8dSAndroid Build Coastguard Worker
964*cda5da8dSAndroid Build Coastguard Worker        An empty string is returned if the value cannot be
965*cda5da8dSAndroid Build Coastguard Worker        determined. Note that many platforms do not provide this
966*cda5da8dSAndroid Build Coastguard Worker        information or simply return the same value as for machine(),
967*cda5da8dSAndroid Build Coastguard Worker        e.g.  NetBSD does this.
968*cda5da8dSAndroid Build Coastguard Worker
969*cda5da8dSAndroid Build Coastguard Worker    """
970*cda5da8dSAndroid Build Coastguard Worker    return uname().processor
971*cda5da8dSAndroid Build Coastguard Worker
972*cda5da8dSAndroid Build Coastguard Worker### Various APIs for extracting information from sys.version
973*cda5da8dSAndroid Build Coastguard Worker
974*cda5da8dSAndroid Build Coastguard Worker_sys_version_parser = re.compile(
975*cda5da8dSAndroid Build Coastguard Worker    r'([\w.+]+)\s*'  # "version<space>"
976*cda5da8dSAndroid Build Coastguard Worker    r'\(#?([^,]+)'  # "(#buildno"
977*cda5da8dSAndroid Build Coastguard Worker    r'(?:,\s*([\w ]*)'  # ", builddate"
978*cda5da8dSAndroid Build Coastguard Worker    r'(?:,\s*([\w :]*))?)?\)\s*'  # ", buildtime)<space>"
979*cda5da8dSAndroid Build Coastguard Worker    r'\[([^\]]+)\]?', re.ASCII)  # "[compiler]"
980*cda5da8dSAndroid Build Coastguard Worker
981*cda5da8dSAndroid Build Coastguard Worker_ironpython_sys_version_parser = re.compile(
982*cda5da8dSAndroid Build Coastguard Worker    r'IronPython\s*'
983*cda5da8dSAndroid Build Coastguard Worker    r'([\d\.]+)'
984*cda5da8dSAndroid Build Coastguard Worker    r'(?: \(([\d\.]+)\))?'
985*cda5da8dSAndroid Build Coastguard Worker    r' on (.NET [\d\.]+)', re.ASCII)
986*cda5da8dSAndroid Build Coastguard Worker
987*cda5da8dSAndroid Build Coastguard Worker# IronPython covering 2.6 and 2.7
988*cda5da8dSAndroid Build Coastguard Worker_ironpython26_sys_version_parser = re.compile(
989*cda5da8dSAndroid Build Coastguard Worker    r'([\d.]+)\s*'
990*cda5da8dSAndroid Build Coastguard Worker    r'\(IronPython\s*'
991*cda5da8dSAndroid Build Coastguard Worker    r'[\d.]+\s*'
992*cda5da8dSAndroid Build Coastguard Worker    r'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
993*cda5da8dSAndroid Build Coastguard Worker)
994*cda5da8dSAndroid Build Coastguard Worker
995*cda5da8dSAndroid Build Coastguard Worker_pypy_sys_version_parser = re.compile(
996*cda5da8dSAndroid Build Coastguard Worker    r'([\w.+]+)\s*'
997*cda5da8dSAndroid Build Coastguard Worker    r'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
998*cda5da8dSAndroid Build Coastguard Worker    r'\[PyPy [^\]]+\]?')
999*cda5da8dSAndroid Build Coastguard Worker
1000*cda5da8dSAndroid Build Coastguard Worker_sys_version_cache = {}
1001*cda5da8dSAndroid Build Coastguard Worker
1002*cda5da8dSAndroid Build Coastguard Workerdef _sys_version(sys_version=None):
1003*cda5da8dSAndroid Build Coastguard Worker
1004*cda5da8dSAndroid Build Coastguard Worker    """ Returns a parsed version of Python's sys.version as tuple
1005*cda5da8dSAndroid Build Coastguard Worker        (name, version, branch, revision, buildno, builddate, compiler)
1006*cda5da8dSAndroid Build Coastguard Worker        referring to the Python implementation name, version, branch,
1007*cda5da8dSAndroid Build Coastguard Worker        revision, build number, build date/time as string and the compiler
1008*cda5da8dSAndroid Build Coastguard Worker        identification string.
1009*cda5da8dSAndroid Build Coastguard Worker
1010*cda5da8dSAndroid Build Coastguard Worker        Note that unlike the Python sys.version, the returned value
1011*cda5da8dSAndroid Build Coastguard Worker        for the Python version will always include the patchlevel (it
1012*cda5da8dSAndroid Build Coastguard Worker        defaults to '.0').
1013*cda5da8dSAndroid Build Coastguard Worker
1014*cda5da8dSAndroid Build Coastguard Worker        The function returns empty strings for tuple entries that
1015*cda5da8dSAndroid Build Coastguard Worker        cannot be determined.
1016*cda5da8dSAndroid Build Coastguard Worker
1017*cda5da8dSAndroid Build Coastguard Worker        sys_version may be given to parse an alternative version
1018*cda5da8dSAndroid Build Coastguard Worker        string, e.g. if the version was read from a different Python
1019*cda5da8dSAndroid Build Coastguard Worker        interpreter.
1020*cda5da8dSAndroid Build Coastguard Worker
1021*cda5da8dSAndroid Build Coastguard Worker    """
1022*cda5da8dSAndroid Build Coastguard Worker    # Get the Python version
1023*cda5da8dSAndroid Build Coastguard Worker    if sys_version is None:
1024*cda5da8dSAndroid Build Coastguard Worker        sys_version = sys.version
1025*cda5da8dSAndroid Build Coastguard Worker
1026*cda5da8dSAndroid Build Coastguard Worker    # Try the cache first
1027*cda5da8dSAndroid Build Coastguard Worker    result = _sys_version_cache.get(sys_version, None)
1028*cda5da8dSAndroid Build Coastguard Worker    if result is not None:
1029*cda5da8dSAndroid Build Coastguard Worker        return result
1030*cda5da8dSAndroid Build Coastguard Worker
1031*cda5da8dSAndroid Build Coastguard Worker    # Parse it
1032*cda5da8dSAndroid Build Coastguard Worker    if 'IronPython' in sys_version:
1033*cda5da8dSAndroid Build Coastguard Worker        # IronPython
1034*cda5da8dSAndroid Build Coastguard Worker        name = 'IronPython'
1035*cda5da8dSAndroid Build Coastguard Worker        if sys_version.startswith('IronPython'):
1036*cda5da8dSAndroid Build Coastguard Worker            match = _ironpython_sys_version_parser.match(sys_version)
1037*cda5da8dSAndroid Build Coastguard Worker        else:
1038*cda5da8dSAndroid Build Coastguard Worker            match = _ironpython26_sys_version_parser.match(sys_version)
1039*cda5da8dSAndroid Build Coastguard Worker
1040*cda5da8dSAndroid Build Coastguard Worker        if match is None:
1041*cda5da8dSAndroid Build Coastguard Worker            raise ValueError(
1042*cda5da8dSAndroid Build Coastguard Worker                'failed to parse IronPython sys.version: %s' %
1043*cda5da8dSAndroid Build Coastguard Worker                repr(sys_version))
1044*cda5da8dSAndroid Build Coastguard Worker
1045*cda5da8dSAndroid Build Coastguard Worker        version, alt_version, compiler = match.groups()
1046*cda5da8dSAndroid Build Coastguard Worker        buildno = ''
1047*cda5da8dSAndroid Build Coastguard Worker        builddate = ''
1048*cda5da8dSAndroid Build Coastguard Worker
1049*cda5da8dSAndroid Build Coastguard Worker    elif sys.platform.startswith('java'):
1050*cda5da8dSAndroid Build Coastguard Worker        # Jython
1051*cda5da8dSAndroid Build Coastguard Worker        name = 'Jython'
1052*cda5da8dSAndroid Build Coastguard Worker        match = _sys_version_parser.match(sys_version)
1053*cda5da8dSAndroid Build Coastguard Worker        if match is None:
1054*cda5da8dSAndroid Build Coastguard Worker            raise ValueError(
1055*cda5da8dSAndroid Build Coastguard Worker                'failed to parse Jython sys.version: %s' %
1056*cda5da8dSAndroid Build Coastguard Worker                repr(sys_version))
1057*cda5da8dSAndroid Build Coastguard Worker        version, buildno, builddate, buildtime, _ = match.groups()
1058*cda5da8dSAndroid Build Coastguard Worker        if builddate is None:
1059*cda5da8dSAndroid Build Coastguard Worker            builddate = ''
1060*cda5da8dSAndroid Build Coastguard Worker        compiler = sys.platform
1061*cda5da8dSAndroid Build Coastguard Worker
1062*cda5da8dSAndroid Build Coastguard Worker    elif "PyPy" in sys_version:
1063*cda5da8dSAndroid Build Coastguard Worker        # PyPy
1064*cda5da8dSAndroid Build Coastguard Worker        name = "PyPy"
1065*cda5da8dSAndroid Build Coastguard Worker        match = _pypy_sys_version_parser.match(sys_version)
1066*cda5da8dSAndroid Build Coastguard Worker        if match is None:
1067*cda5da8dSAndroid Build Coastguard Worker            raise ValueError("failed to parse PyPy sys.version: %s" %
1068*cda5da8dSAndroid Build Coastguard Worker                             repr(sys_version))
1069*cda5da8dSAndroid Build Coastguard Worker        version, buildno, builddate, buildtime = match.groups()
1070*cda5da8dSAndroid Build Coastguard Worker        compiler = ""
1071*cda5da8dSAndroid Build Coastguard Worker
1072*cda5da8dSAndroid Build Coastguard Worker    else:
1073*cda5da8dSAndroid Build Coastguard Worker        # CPython
1074*cda5da8dSAndroid Build Coastguard Worker        match = _sys_version_parser.match(sys_version)
1075*cda5da8dSAndroid Build Coastguard Worker        if match is None:
1076*cda5da8dSAndroid Build Coastguard Worker            raise ValueError(
1077*cda5da8dSAndroid Build Coastguard Worker                'failed to parse CPython sys.version: %s' %
1078*cda5da8dSAndroid Build Coastguard Worker                repr(sys_version))
1079*cda5da8dSAndroid Build Coastguard Worker        version, buildno, builddate, buildtime, compiler = \
1080*cda5da8dSAndroid Build Coastguard Worker              match.groups()
1081*cda5da8dSAndroid Build Coastguard Worker        name = 'CPython'
1082*cda5da8dSAndroid Build Coastguard Worker        if builddate is None:
1083*cda5da8dSAndroid Build Coastguard Worker            builddate = ''
1084*cda5da8dSAndroid Build Coastguard Worker        elif buildtime:
1085*cda5da8dSAndroid Build Coastguard Worker            builddate = builddate + ' ' + buildtime
1086*cda5da8dSAndroid Build Coastguard Worker
1087*cda5da8dSAndroid Build Coastguard Worker    if hasattr(sys, '_git'):
1088*cda5da8dSAndroid Build Coastguard Worker        _, branch, revision = sys._git
1089*cda5da8dSAndroid Build Coastguard Worker    elif hasattr(sys, '_mercurial'):
1090*cda5da8dSAndroid Build Coastguard Worker        _, branch, revision = sys._mercurial
1091*cda5da8dSAndroid Build Coastguard Worker    else:
1092*cda5da8dSAndroid Build Coastguard Worker        branch = ''
1093*cda5da8dSAndroid Build Coastguard Worker        revision = ''
1094*cda5da8dSAndroid Build Coastguard Worker
1095*cda5da8dSAndroid Build Coastguard Worker    # Add the patchlevel version if missing
1096*cda5da8dSAndroid Build Coastguard Worker    l = version.split('.')
1097*cda5da8dSAndroid Build Coastguard Worker    if len(l) == 2:
1098*cda5da8dSAndroid Build Coastguard Worker        l.append('0')
1099*cda5da8dSAndroid Build Coastguard Worker        version = '.'.join(l)
1100*cda5da8dSAndroid Build Coastguard Worker
1101*cda5da8dSAndroid Build Coastguard Worker    # Build and cache the result
1102*cda5da8dSAndroid Build Coastguard Worker    result = (name, version, branch, revision, buildno, builddate, compiler)
1103*cda5da8dSAndroid Build Coastguard Worker    _sys_version_cache[sys_version] = result
1104*cda5da8dSAndroid Build Coastguard Worker    return result
1105*cda5da8dSAndroid Build Coastguard Worker
1106*cda5da8dSAndroid Build Coastguard Workerdef python_implementation():
1107*cda5da8dSAndroid Build Coastguard Worker
1108*cda5da8dSAndroid Build Coastguard Worker    """ Returns a string identifying the Python implementation.
1109*cda5da8dSAndroid Build Coastguard Worker
1110*cda5da8dSAndroid Build Coastguard Worker        Currently, the following implementations are identified:
1111*cda5da8dSAndroid Build Coastguard Worker          'CPython' (C implementation of Python),
1112*cda5da8dSAndroid Build Coastguard Worker          'IronPython' (.NET implementation of Python),
1113*cda5da8dSAndroid Build Coastguard Worker          'Jython' (Java implementation of Python),
1114*cda5da8dSAndroid Build Coastguard Worker          'PyPy' (Python implementation of Python).
1115*cda5da8dSAndroid Build Coastguard Worker
1116*cda5da8dSAndroid Build Coastguard Worker    """
1117*cda5da8dSAndroid Build Coastguard Worker    return _sys_version()[0]
1118*cda5da8dSAndroid Build Coastguard Worker
1119*cda5da8dSAndroid Build Coastguard Workerdef python_version():
1120*cda5da8dSAndroid Build Coastguard Worker
1121*cda5da8dSAndroid Build Coastguard Worker    """ Returns the Python version as string 'major.minor.patchlevel'
1122*cda5da8dSAndroid Build Coastguard Worker
1123*cda5da8dSAndroid Build Coastguard Worker        Note that unlike the Python sys.version, the returned value
1124*cda5da8dSAndroid Build Coastguard Worker        will always include the patchlevel (it defaults to 0).
1125*cda5da8dSAndroid Build Coastguard Worker
1126*cda5da8dSAndroid Build Coastguard Worker    """
1127*cda5da8dSAndroid Build Coastguard Worker    return _sys_version()[1]
1128*cda5da8dSAndroid Build Coastguard Worker
1129*cda5da8dSAndroid Build Coastguard Workerdef python_version_tuple():
1130*cda5da8dSAndroid Build Coastguard Worker
1131*cda5da8dSAndroid Build Coastguard Worker    """ Returns the Python version as tuple (major, minor, patchlevel)
1132*cda5da8dSAndroid Build Coastguard Worker        of strings.
1133*cda5da8dSAndroid Build Coastguard Worker
1134*cda5da8dSAndroid Build Coastguard Worker        Note that unlike the Python sys.version, the returned value
1135*cda5da8dSAndroid Build Coastguard Worker        will always include the patchlevel (it defaults to 0).
1136*cda5da8dSAndroid Build Coastguard Worker
1137*cda5da8dSAndroid Build Coastguard Worker    """
1138*cda5da8dSAndroid Build Coastguard Worker    return tuple(_sys_version()[1].split('.'))
1139*cda5da8dSAndroid Build Coastguard Worker
1140*cda5da8dSAndroid Build Coastguard Workerdef python_branch():
1141*cda5da8dSAndroid Build Coastguard Worker
1142*cda5da8dSAndroid Build Coastguard Worker    """ Returns a string identifying the Python implementation
1143*cda5da8dSAndroid Build Coastguard Worker        branch.
1144*cda5da8dSAndroid Build Coastguard Worker
1145*cda5da8dSAndroid Build Coastguard Worker        For CPython this is the SCM branch from which the
1146*cda5da8dSAndroid Build Coastguard Worker        Python binary was built.
1147*cda5da8dSAndroid Build Coastguard Worker
1148*cda5da8dSAndroid Build Coastguard Worker        If not available, an empty string is returned.
1149*cda5da8dSAndroid Build Coastguard Worker
1150*cda5da8dSAndroid Build Coastguard Worker    """
1151*cda5da8dSAndroid Build Coastguard Worker
1152*cda5da8dSAndroid Build Coastguard Worker    return _sys_version()[2]
1153*cda5da8dSAndroid Build Coastguard Worker
1154*cda5da8dSAndroid Build Coastguard Workerdef python_revision():
1155*cda5da8dSAndroid Build Coastguard Worker
1156*cda5da8dSAndroid Build Coastguard Worker    """ Returns a string identifying the Python implementation
1157*cda5da8dSAndroid Build Coastguard Worker        revision.
1158*cda5da8dSAndroid Build Coastguard Worker
1159*cda5da8dSAndroid Build Coastguard Worker        For CPython this is the SCM revision from which the
1160*cda5da8dSAndroid Build Coastguard Worker        Python binary was built.
1161*cda5da8dSAndroid Build Coastguard Worker
1162*cda5da8dSAndroid Build Coastguard Worker        If not available, an empty string is returned.
1163*cda5da8dSAndroid Build Coastguard Worker
1164*cda5da8dSAndroid Build Coastguard Worker    """
1165*cda5da8dSAndroid Build Coastguard Worker    return _sys_version()[3]
1166*cda5da8dSAndroid Build Coastguard Worker
1167*cda5da8dSAndroid Build Coastguard Workerdef python_build():
1168*cda5da8dSAndroid Build Coastguard Worker
1169*cda5da8dSAndroid Build Coastguard Worker    """ Returns a tuple (buildno, builddate) stating the Python
1170*cda5da8dSAndroid Build Coastguard Worker        build number and date as strings.
1171*cda5da8dSAndroid Build Coastguard Worker
1172*cda5da8dSAndroid Build Coastguard Worker    """
1173*cda5da8dSAndroid Build Coastguard Worker    return _sys_version()[4:6]
1174*cda5da8dSAndroid Build Coastguard Worker
1175*cda5da8dSAndroid Build Coastguard Workerdef python_compiler():
1176*cda5da8dSAndroid Build Coastguard Worker
1177*cda5da8dSAndroid Build Coastguard Worker    """ Returns a string identifying the compiler used for compiling
1178*cda5da8dSAndroid Build Coastguard Worker        Python.
1179*cda5da8dSAndroid Build Coastguard Worker
1180*cda5da8dSAndroid Build Coastguard Worker    """
1181*cda5da8dSAndroid Build Coastguard Worker    return _sys_version()[6]
1182*cda5da8dSAndroid Build Coastguard Worker
1183*cda5da8dSAndroid Build Coastguard Worker### The Opus Magnum of platform strings :-)
1184*cda5da8dSAndroid Build Coastguard Worker
1185*cda5da8dSAndroid Build Coastguard Worker_platform_cache = {}
1186*cda5da8dSAndroid Build Coastguard Worker
1187*cda5da8dSAndroid Build Coastguard Workerdef platform(aliased=0, terse=0):
1188*cda5da8dSAndroid Build Coastguard Worker
1189*cda5da8dSAndroid Build Coastguard Worker    """ Returns a single string identifying the underlying platform
1190*cda5da8dSAndroid Build Coastguard Worker        with as much useful information as possible (but no more :).
1191*cda5da8dSAndroid Build Coastguard Worker
1192*cda5da8dSAndroid Build Coastguard Worker        The output is intended to be human readable rather than
1193*cda5da8dSAndroid Build Coastguard Worker        machine parseable. It may look different on different
1194*cda5da8dSAndroid Build Coastguard Worker        platforms and this is intended.
1195*cda5da8dSAndroid Build Coastguard Worker
1196*cda5da8dSAndroid Build Coastguard Worker        If "aliased" is true, the function will use aliases for
1197*cda5da8dSAndroid Build Coastguard Worker        various platforms that report system names which differ from
1198*cda5da8dSAndroid Build Coastguard Worker        their common names, e.g. SunOS will be reported as
1199*cda5da8dSAndroid Build Coastguard Worker        Solaris. The system_alias() function is used to implement
1200*cda5da8dSAndroid Build Coastguard Worker        this.
1201*cda5da8dSAndroid Build Coastguard Worker
1202*cda5da8dSAndroid Build Coastguard Worker        Setting terse to true causes the function to return only the
1203*cda5da8dSAndroid Build Coastguard Worker        absolute minimum information needed to identify the platform.
1204*cda5da8dSAndroid Build Coastguard Worker
1205*cda5da8dSAndroid Build Coastguard Worker    """
1206*cda5da8dSAndroid Build Coastguard Worker    result = _platform_cache.get((aliased, terse), None)
1207*cda5da8dSAndroid Build Coastguard Worker    if result is not None:
1208*cda5da8dSAndroid Build Coastguard Worker        return result
1209*cda5da8dSAndroid Build Coastguard Worker
1210*cda5da8dSAndroid Build Coastguard Worker    # Get uname information and then apply platform specific cosmetics
1211*cda5da8dSAndroid Build Coastguard Worker    # to it...
1212*cda5da8dSAndroid Build Coastguard Worker    system, node, release, version, machine, processor = uname()
1213*cda5da8dSAndroid Build Coastguard Worker    if machine == processor:
1214*cda5da8dSAndroid Build Coastguard Worker        processor = ''
1215*cda5da8dSAndroid Build Coastguard Worker    if aliased:
1216*cda5da8dSAndroid Build Coastguard Worker        system, release, version = system_alias(system, release, version)
1217*cda5da8dSAndroid Build Coastguard Worker
1218*cda5da8dSAndroid Build Coastguard Worker    if system == 'Darwin':
1219*cda5da8dSAndroid Build Coastguard Worker        # macOS (darwin kernel)
1220*cda5da8dSAndroid Build Coastguard Worker        macos_release = mac_ver()[0]
1221*cda5da8dSAndroid Build Coastguard Worker        if macos_release:
1222*cda5da8dSAndroid Build Coastguard Worker            system = 'macOS'
1223*cda5da8dSAndroid Build Coastguard Worker            release = macos_release
1224*cda5da8dSAndroid Build Coastguard Worker
1225*cda5da8dSAndroid Build Coastguard Worker    if system == 'Windows':
1226*cda5da8dSAndroid Build Coastguard Worker        # MS platforms
1227*cda5da8dSAndroid Build Coastguard Worker        rel, vers, csd, ptype = win32_ver(version)
1228*cda5da8dSAndroid Build Coastguard Worker        if terse:
1229*cda5da8dSAndroid Build Coastguard Worker            platform = _platform(system, release)
1230*cda5da8dSAndroid Build Coastguard Worker        else:
1231*cda5da8dSAndroid Build Coastguard Worker            platform = _platform(system, release, version, csd)
1232*cda5da8dSAndroid Build Coastguard Worker
1233*cda5da8dSAndroid Build Coastguard Worker    elif system in ('Linux',):
1234*cda5da8dSAndroid Build Coastguard Worker        # check for libc vs. glibc
1235*cda5da8dSAndroid Build Coastguard Worker        libcname, libcversion = libc_ver()
1236*cda5da8dSAndroid Build Coastguard Worker        platform = _platform(system, release, machine, processor,
1237*cda5da8dSAndroid Build Coastguard Worker                             'with',
1238*cda5da8dSAndroid Build Coastguard Worker                             libcname+libcversion)
1239*cda5da8dSAndroid Build Coastguard Worker    elif system == 'Java':
1240*cda5da8dSAndroid Build Coastguard Worker        # Java platforms
1241*cda5da8dSAndroid Build Coastguard Worker        r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
1242*cda5da8dSAndroid Build Coastguard Worker        if terse or not os_name:
1243*cda5da8dSAndroid Build Coastguard Worker            platform = _platform(system, release, version)
1244*cda5da8dSAndroid Build Coastguard Worker        else:
1245*cda5da8dSAndroid Build Coastguard Worker            platform = _platform(system, release, version,
1246*cda5da8dSAndroid Build Coastguard Worker                                 'on',
1247*cda5da8dSAndroid Build Coastguard Worker                                 os_name, os_version, os_arch)
1248*cda5da8dSAndroid Build Coastguard Worker
1249*cda5da8dSAndroid Build Coastguard Worker    else:
1250*cda5da8dSAndroid Build Coastguard Worker        # Generic handler
1251*cda5da8dSAndroid Build Coastguard Worker        if terse:
1252*cda5da8dSAndroid Build Coastguard Worker            platform = _platform(system, release)
1253*cda5da8dSAndroid Build Coastguard Worker        else:
1254*cda5da8dSAndroid Build Coastguard Worker            bits, linkage = architecture(sys.executable)
1255*cda5da8dSAndroid Build Coastguard Worker            platform = _platform(system, release, machine,
1256*cda5da8dSAndroid Build Coastguard Worker                                 processor, bits, linkage)
1257*cda5da8dSAndroid Build Coastguard Worker
1258*cda5da8dSAndroid Build Coastguard Worker    _platform_cache[(aliased, terse)] = platform
1259*cda5da8dSAndroid Build Coastguard Worker    return platform
1260*cda5da8dSAndroid Build Coastguard Worker
1261*cda5da8dSAndroid Build Coastguard Worker### freedesktop.org os-release standard
1262*cda5da8dSAndroid Build Coastguard Worker# https://www.freedesktop.org/software/systemd/man/os-release.html
1263*cda5da8dSAndroid Build Coastguard Worker
1264*cda5da8dSAndroid Build Coastguard Worker# NAME=value with optional quotes (' or "). The regular expression is less
1265*cda5da8dSAndroid Build Coastguard Worker# strict than shell lexer, but that's ok.
1266*cda5da8dSAndroid Build Coastguard Worker_os_release_line = re.compile(
1267*cda5da8dSAndroid Build Coastguard Worker    "^(?P<name>[a-zA-Z0-9_]+)=(?P<quote>[\"\']?)(?P<value>.*)(?P=quote)$"
1268*cda5da8dSAndroid Build Coastguard Worker)
1269*cda5da8dSAndroid Build Coastguard Worker# unescape five special characters mentioned in the standard
1270*cda5da8dSAndroid Build Coastguard Worker_os_release_unescape = re.compile(r"\\([\\\$\"\'`])")
1271*cda5da8dSAndroid Build Coastguard Worker# /etc takes precedence over /usr/lib
1272*cda5da8dSAndroid Build Coastguard Worker_os_release_candidates = ("/etc/os-release", "/usr/lib/os-release")
1273*cda5da8dSAndroid Build Coastguard Worker_os_release_cache = None
1274*cda5da8dSAndroid Build Coastguard Worker
1275*cda5da8dSAndroid Build Coastguard Worker
1276*cda5da8dSAndroid Build Coastguard Workerdef _parse_os_release(lines):
1277*cda5da8dSAndroid Build Coastguard Worker    # These fields are mandatory fields with well-known defaults
1278*cda5da8dSAndroid Build Coastguard Worker    # in practice all Linux distributions override NAME, ID, and PRETTY_NAME.
1279*cda5da8dSAndroid Build Coastguard Worker    info = {
1280*cda5da8dSAndroid Build Coastguard Worker        "NAME": "Linux",
1281*cda5da8dSAndroid Build Coastguard Worker        "ID": "linux",
1282*cda5da8dSAndroid Build Coastguard Worker        "PRETTY_NAME": "Linux",
1283*cda5da8dSAndroid Build Coastguard Worker    }
1284*cda5da8dSAndroid Build Coastguard Worker
1285*cda5da8dSAndroid Build Coastguard Worker    for line in lines:
1286*cda5da8dSAndroid Build Coastguard Worker        mo = _os_release_line.match(line)
1287*cda5da8dSAndroid Build Coastguard Worker        if mo is not None:
1288*cda5da8dSAndroid Build Coastguard Worker            info[mo.group('name')] = _os_release_unescape.sub(
1289*cda5da8dSAndroid Build Coastguard Worker                r"\1", mo.group('value')
1290*cda5da8dSAndroid Build Coastguard Worker            )
1291*cda5da8dSAndroid Build Coastguard Worker
1292*cda5da8dSAndroid Build Coastguard Worker    return info
1293*cda5da8dSAndroid Build Coastguard Worker
1294*cda5da8dSAndroid Build Coastguard Worker
1295*cda5da8dSAndroid Build Coastguard Workerdef freedesktop_os_release():
1296*cda5da8dSAndroid Build Coastguard Worker    """Return operation system identification from freedesktop.org os-release
1297*cda5da8dSAndroid Build Coastguard Worker    """
1298*cda5da8dSAndroid Build Coastguard Worker    global _os_release_cache
1299*cda5da8dSAndroid Build Coastguard Worker
1300*cda5da8dSAndroid Build Coastguard Worker    if _os_release_cache is None:
1301*cda5da8dSAndroid Build Coastguard Worker        errno = None
1302*cda5da8dSAndroid Build Coastguard Worker        for candidate in _os_release_candidates:
1303*cda5da8dSAndroid Build Coastguard Worker            try:
1304*cda5da8dSAndroid Build Coastguard Worker                with open(candidate, encoding="utf-8") as f:
1305*cda5da8dSAndroid Build Coastguard Worker                    _os_release_cache = _parse_os_release(f)
1306*cda5da8dSAndroid Build Coastguard Worker                break
1307*cda5da8dSAndroid Build Coastguard Worker            except OSError as e:
1308*cda5da8dSAndroid Build Coastguard Worker                errno = e.errno
1309*cda5da8dSAndroid Build Coastguard Worker        else:
1310*cda5da8dSAndroid Build Coastguard Worker            raise OSError(
1311*cda5da8dSAndroid Build Coastguard Worker                errno,
1312*cda5da8dSAndroid Build Coastguard Worker                f"Unable to read files {', '.join(_os_release_candidates)}"
1313*cda5da8dSAndroid Build Coastguard Worker            )
1314*cda5da8dSAndroid Build Coastguard Worker
1315*cda5da8dSAndroid Build Coastguard Worker    return _os_release_cache.copy()
1316*cda5da8dSAndroid Build Coastguard Worker
1317*cda5da8dSAndroid Build Coastguard Worker
1318*cda5da8dSAndroid Build Coastguard Worker### Command line interface
1319*cda5da8dSAndroid Build Coastguard Worker
1320*cda5da8dSAndroid Build Coastguard Workerif __name__ == '__main__':
1321*cda5da8dSAndroid Build Coastguard Worker    # Default is to print the aliased verbose platform string
1322*cda5da8dSAndroid Build Coastguard Worker    terse = ('terse' in sys.argv or '--terse' in sys.argv)
1323*cda5da8dSAndroid Build Coastguard Worker    aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
1324*cda5da8dSAndroid Build Coastguard Worker    print(platform(aliased, terse))
1325*cda5da8dSAndroid Build Coastguard Worker    sys.exit(0)
1326