mirror of
https://github.com/HorlogeSkynet/archey4
synced 2024-11-25 04:00:10 +01:00
145 lines
5.3 KiB
Python
145 lines
5.3 KiB
Python
"""
|
|
Distributions enumeration module.
|
|
Operating Systems detection logic.
|
|
Interface to `os-release` (through `distro` module).
|
|
"""
|
|
|
|
import os
|
|
import platform
|
|
import sys
|
|
|
|
from enum import Enum
|
|
from functools import lru_cache
|
|
from typing import List, Optional
|
|
|
|
import distro
|
|
|
|
|
|
class Distributions(Enum):
|
|
"""
|
|
This enumeration lists supported operating systems (keys).
|
|
Values contain their respective `distro` identifier.
|
|
See <https://distro.readthedocs.io/en/latest/#distro.id>.
|
|
"""
|
|
ALPINE = 'alpine'
|
|
ANDROID = 'android'
|
|
ARCH = 'arch'
|
|
BUNSENLABS = 'bunsenlabs'
|
|
CENTOS = 'centos'
|
|
CRUNCHBANG = 'crunchbang'
|
|
DARWIN = 'darwin'
|
|
DEBIAN = 'debian'
|
|
DEVUAN = 'devuan'
|
|
ELEMENTARY = 'elementary'
|
|
FEDORA = 'fedora'
|
|
FREEBSD = 'freebsd'
|
|
GENTOO = 'gentoo'
|
|
KALI = 'kali'
|
|
MANJARO = 'manjaro'
|
|
NETBSD = 'netbsd'
|
|
NIXOS = 'nixos'
|
|
LINUX = 'linux'
|
|
LINUXMINT = 'linuxmint'
|
|
OPENBSD = 'openbsd'
|
|
OPENSUSE = 'opensuse'
|
|
POP = 'pop'
|
|
PARABOLA = 'parabola'
|
|
RASPBIAN = 'raspbian'
|
|
RHEL = 'rhel'
|
|
SLACKWARE = 'slackware'
|
|
UBUNTU = 'ubuntu'
|
|
WINDOWS = 'windows'
|
|
|
|
|
|
@staticmethod
|
|
def get_identifiers() -> List[str]:
|
|
"""Simple getter returning current supported distributions identifiers"""
|
|
return [d.value for d in Distributions.__members__.values()]
|
|
|
|
@staticmethod
|
|
@lru_cache(maxsize=None) # Python < 3.9, `functools.cache` is not yet available.
|
|
def get_local() -> 'Distributions':
|
|
"""Entry point of Archey distribution detection logic"""
|
|
distribution = Distributions._vendor_detection()
|
|
|
|
# In case nothing got detected the "regular" way...
|
|
if not distribution:
|
|
# Are we running on Darwin (somehow not previously detected by `distro`) ?
|
|
if platform.system() == 'Darwin':
|
|
return Distributions.DARWIN
|
|
|
|
# Android systems are currently not being handled by `distro`.
|
|
# At first, we imitate the Python standard library, by checking whether CPython
|
|
# has been built for Android.
|
|
# See <https://github.com/python/cpython/search?l=Python&q=getandroidapilevel>
|
|
# As a fallback, we mimic Neofetch behavior, by relying on the file-system.
|
|
# See <https://github.com/nir0s/distro/issues/253>
|
|
if hasattr(sys, 'getandroidapilevel') \
|
|
or (os.path.isdir('/system/app') and os.path.isdir('/system/priv-app')):
|
|
return Distributions.ANDROID
|
|
|
|
# If nothing of the above matched, fall-back on the Linux logo.
|
|
return Distributions.LINUX
|
|
|
|
# Below are brain-dead cases for distributions not properly handled by `distro`.
|
|
# One _may_ want to add its own logic to add support for such undetectable systems.
|
|
if distribution == Distributions.DEBIAN:
|
|
# CrunchBang is tagged as _regular_ Debian by `distro`.
|
|
# Below conditions are here to work-around this issue.
|
|
# First condition : CrunchBang-Linux and CrunchBang-Monara.
|
|
# Second condition : CrunchBang++ (CBPP).
|
|
if os.path.isfile('/etc/lsb-release-crunchbang') \
|
|
or os.path.isfile('/usr/bin/cbpp-exit'):
|
|
return Distributions.CRUNCHBANG
|
|
|
|
elif distribution == Distributions.UBUNTU:
|
|
# Older Pop!_OS releases (< 20.*) didn't ship their own `ID` (from `os-release`).
|
|
# Thus, they are detected as "regular" Ubuntu distributions.
|
|
# We may here rely on their `NAME` (from `os-release`), which is sufficient.
|
|
if Distributions.get_distro_name(pretty=False) == 'Pop!_OS':
|
|
return Distributions.POP
|
|
|
|
return distribution
|
|
|
|
@staticmethod
|
|
def _vendor_detection() -> Optional['Distributions']:
|
|
"""Main distribution detection logic, relying on `distro`, handling _common_ cases"""
|
|
# Are we running on Windows ?
|
|
if platform.system() == 'Windows':
|
|
return Distributions.WINDOWS
|
|
|
|
# Is it a Windows Sub-system Linux (WSL) distribution ?
|
|
# If so, kernel release identifier should keep a trace of it.
|
|
if 'microsoft' in platform.release().lower():
|
|
return Distributions.WINDOWS
|
|
|
|
# Is `ID` (from `os-release`) well-known and supported ?
|
|
try:
|
|
return Distributions(distro.id())
|
|
except ValueError:
|
|
pass
|
|
|
|
# Is any of `ID_LIKE` (from `os-release`) well-known and supported ?
|
|
# See <https://www.freedesktop.org/software/systemd/man/os-release.html#ID_LIKE=>.
|
|
for id_like in distro.like().split(' '):
|
|
try:
|
|
return Distributions(id_like)
|
|
except ValueError:
|
|
pass
|
|
|
|
# Nothing of the above matched, let's return `None` and let the caller handle it.
|
|
return None
|
|
|
|
@staticmethod
|
|
def get_distro_name(pretty: bool = True) -> Optional[str]:
|
|
"""Simple wrapper to `distro` to return the current distribution _pretty_ name"""
|
|
return distro.name(pretty=pretty) or None
|
|
|
|
@staticmethod
|
|
def get_ansi_color() -> Optional[str]:
|
|
"""
|
|
Simple wrapper to `distro` to return the distribution preferred ANSI color.
|
|
See <https://www.freedesktop.org/software/systemd/man/os-release.html#ANSI_COLOR=>.
|
|
"""
|
|
return distro.os_release_attr('ansi_color') or None
|