Coverage for src/system/platform.py: 100.00%
63 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-10-18 15:02 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-10-18 15:02 +0000
1#!/usr/bin/env python3
3# Standard libraries
4from os import access, environ, R_OK, sep
5from os.path import expanduser
6from pathlib import Path, PurePosixPath
7from sys import platform, stdin, stdout
8from typing import List
10# Platform
11class Platform:
13 # Environment
14 ENV_ANDROID: str = 'ANDROID_ROOT'
15 ENV_DISPLAY: str = 'DISPLAY'
16 ENV_EXPERIMENTAL: str = 'EXPERIMENTAL'
17 ENV_SIMULATE_MAC_OS: str = 'SIMULATE_MAC_OS'
18 ENV_SSH_AUTH_SOCK: str = 'SSH_AUTH_SOCK'
19 ENV_SUDO_USER: str = 'SUDO_USER'
20 ENV_XAUTHORITY: str = 'XAUTHORITY'
22 # Constants
23 IS_ANDROID: bool = 'ANDROID_ROOT' in environ
24 IS_EXPERIMENTAL: bool = ENV_EXPERIMENTAL in environ
25 IS_LINUX: bool = platform in ['linux', 'linux2']
26 IS_MAC_OS: bool = platform in ['darwin'] or ENV_SIMULATE_MAC_OS in environ
27 IS_SIMULATED: bool = ENV_SIMULATE_MAC_OS in environ
28 IS_WINDOWS: bool = platform in ['win32', 'win64']
30 # Paths
31 BUILDS_DIR: PurePosixPath = PurePosixPath('/builds')
33 # Separators
34 PATH_SEPARATOR: str = sep
36 # Sockets
37 SOCKET_DISPLAY_LINUX: str = '/tmp/.X11-unix'
39 # TTYs
40 IS_TTY_STDIN: bool = stdin.isatty() and stdin.encoding != 'cp1252'
41 IS_TTY_STDOUT: bool = stdout.isatty()
42 IS_TTY_UTF8: bool = str(stdout.encoding).lower() == 'utf-8'
44 # Outputs
45 IS_FLUSH_ENABLED: bool = IS_TTY_STDOUT or IS_WINDOWS
47 # Users
48 IS_USER_SUDO: bool = ENV_SUDO_USER in environ
49 USER_SUDO: str = environ[ENV_SUDO_USER] if IS_USER_SUDO else ''
51 # Display
52 @staticmethod
53 def display() -> List[str]:
55 # Variables
56 sockets: List[str] = []
58 # Linux display
59 if Platform.IS_LINUX:
60 if Path(Platform.SOCKET_DISPLAY_LINUX).exists(): # pragma: no cover
61 sockets += [Platform.SOCKET_DISPLAY_LINUX]
62 if environ.get(Platform.ENV_XAUTHORITY, '') and Path(
63 environ[Platform.ENV_XAUTHORITY]).exists(): # pragma: no cover
64 sockets += [environ[Platform.ENV_XAUTHORITY]]
66 # Result
67 return sockets
69 # Flush
70 @staticmethod
71 def flush() -> None:
73 # Flush output
74 print(
75 '',
76 end='',
77 flush=Platform.IS_FLUSH_ENABLED,
78 )
80 # Get GID
81 @staticmethod
82 def getgid() -> int:
84 # Result, pylint: disable=import-outside-toplevel
85 try:
86 from os import getgid
87 return getgid()
88 except ImportError: # pragma: no cover
89 return 0
91 # Get UID
92 @staticmethod
93 def getuid() -> int:
95 # Result, pylint: disable=import-outside-toplevel
96 try:
97 from os import getuid
98 return getuid()
99 except ImportError: # pragma: no cover
100 return 0
102 # Get username
103 @staticmethod
104 def getusername() -> str:
106 # Result, pylint: disable=import-outside-toplevel
107 try:
108 from getpass import getuser
109 return getuser()
110 except ImportError: # pragma: no cover
111 return 'root'
113 # Userspace
114 @staticmethod
115 def userspace(name: str) -> Path:
117 # Variables
118 home: None | Path = None
120 # Elevated home
121 if Platform.IS_USER_SUDO: # pragma: linux cover
122 home = Path(expanduser(f'~{Platform.USER_SUDO}'))
123 if not access(home, R_OK): # pragma: no cover
124 home = None
126 # Default home
127 if not home or not home.is_dir():
128 home = Path.home()
130 # Windows userspace
131 if Platform.IS_WINDOWS: # pragma: windows cover
132 return home / 'AppData' / 'Local' / name
134 # macOS userspace
135 if Platform.IS_MAC_OS: # pragma: macos cover
136 return home / 'Library' / 'Preferences' / name
138 # Linux userspace
139 return home / '.config' / name # pragma: linux cover