1# Copyright 2021, Kay Hayen, mailto:kay.hayen@gmail.com 2# 3# Part of "Nuitka", an optimizing Python compiler that is compatible and 4# integrates with CPython, but also works on its own. 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18""" Utility module. 19 20Here the small things that fit nowhere else and don't deserve their own module. 21 22""" 23 24import os 25import platform 26import sys 27 28from nuitka.PythonVersions import python_version 29 30 31def getOS(): 32 if os.name == "nt": 33 return "Windows" 34 elif os.name == "posix": 35 result = os.uname()[0] 36 37 # Handle msys2 posix nature still meaning it's Windows. 38 if result.startswith(("MSYS_NT-", "MINGW64_NT-")): 39 result = "Windows" 40 41 return result 42 else: 43 assert False, os.name 44 45 46_linux_distribution = None 47 48 49def getLinuxDistribution(): 50 """Name of the Linux distribution. 51 52 We should usually avoid this, and rather test for the feature, 53 but in some cases it's hard to manage that. 54 """ 55 # singleton, pylint: disable=global-statement 56 global _linux_distribution 57 58 if getOS() != "Linux": 59 return None 60 61 if _linux_distribution is None: 62 # pylint: disable=I0021,deprecated-method,no-member 63 try: 64 result = platform.dist()[0].title() 65 except AttributeError: 66 from .Execution import check_output 67 68 try: 69 result = check_output(["lsb_release", "-i", "-s"], shell=False).title() 70 71 if str is not bytes: 72 result = result.decode("utf8") 73 except FileNotFoundError: 74 from .FileOperations import getFileContentByLine 75 76 for line in getFileContentByLine("/etc/os-release"): 77 if line.startswith("ID="): 78 result = line[3:] 79 break 80 else: 81 from nuitka.Tracing import general 82 83 general.sysexit("Error, cannot detect Linux distribution.") 84 85 _linux_distribution = result.title() 86 87 return _linux_distribution 88 89 90def isDebianBasedLinux(): 91 # TODO: What is with Mint, maybe others, this list should be expanded potentially. 92 return getLinuxDistribution() in ("Debian", "Ubuntu") 93 94 95def isWin32Windows(): 96 """The Win32 variants of Python does have win32 only, not posix.""" 97 return os.name == "nt" 98 99 100def isPosixWindows(): 101 """The MSYS2 variant of Python does have posix only, not Win32.""" 102 return os.name == "posix" and getOS() == "Windows" 103 104 105_is_alpine = None 106 107 108def isAlpineLinux(): 109 if os.name == "posix": 110 111 # Avoid repeated file system lookup, pylint: disable=global-statement 112 global _is_alpine 113 if _is_alpine is None: 114 _is_alpine = os.path.isfile("/etc/alpine-release") 115 116 return _is_alpine 117 else: 118 return False 119 120 121def getArchitecture(): 122 if getOS() == "Windows": 123 if "AMD64" in sys.version: 124 return "x86_64" 125 else: 126 return "x86" 127 else: 128 return os.uname()[4] 129 130 131def getCoreCount(): 132 cpu_count = 0 133 134 # Try to sum up the CPU cores, if the kernel shows them. 135 try: 136 # Try to get the number of logical processors 137 with open("/proc/cpuinfo") as cpuinfo_file: 138 cpu_count = cpuinfo_file.read().count("processor\t:") 139 except IOError: 140 pass 141 142 if not cpu_count: 143 import multiprocessing 144 145 cpu_count = multiprocessing.cpu_count() 146 147 return cpu_count 148 149 150def encodeNonAscii(var_name): 151 """Encode variable name that is potentially not ASCII to ASCII only. 152 153 For Python3, unicode identifiers can be used, but these are not 154 possible in C, so we need to replace them. 155 """ 156 if python_version < 0x300: 157 return var_name 158 else: 159 # Using a escaping here, because that makes it safe in terms of not 160 # to occur in the encoding escape sequence for unicode use. 161 var_name = var_name.replace("$$", "$_$") 162 163 var_name = var_name.encode("ascii", "xmlcharrefreplace") 164 var_name = var_name.decode("ascii") 165 166 return var_name.replace("&#", "$$").replace(";", "") 167 168 169def hasOnefileSupportedOS(): 170 return getOS() in ("Linux", "Windows", "Darwin", "FreeBSD") 171 172 173def getUserName(): 174 """Return the user name. 175 176 Notes: Currently doesn't work on Windows. 177 """ 178 import pwd # pylint: disable=I0021,import-error 179 180 return pwd.getpwuid(os.getuid())[0] 181