mirror of
https://github.com/HorlogeSkynet/archey4
synced 2024-11-21 20:00:12 +01:00
154 lines
5.7 KiB
Python
154 lines
5.7 KiB
Python
"""
|
|
Distributions enumeration module.
|
|
Operating Systems detection logic.
|
|
Interface to `os-release` (through `distro` module).
|
|
"""
|
|
|
|
import os
|
|
import platform
|
|
import sys
|
|
from contextlib import suppress
|
|
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"
|
|
ARMBIAN = "armbian"
|
|
BUILDROOT = "buildroot"
|
|
BUNSENLABS = "bunsenlabs"
|
|
CENTOS = "centos"
|
|
CRUNCHBANG = "crunchbang"
|
|
DARWIN = "darwin"
|
|
DEBIAN = "debian"
|
|
DEVUAN = "devuan"
|
|
ELEMENTARY = "elementary"
|
|
ENDEAVOUROS = "endeavouros"
|
|
ENSO = "enso"
|
|
FEDORA = "fedora"
|
|
FREEBSD = "freebsd"
|
|
GENTOO = "gentoo"
|
|
GUIX = "guix"
|
|
KALI = "kali"
|
|
MANJARO = "manjaro"
|
|
MOEVALENT = "moevalent"
|
|
NETBSD = "netbsd"
|
|
NIXOS = "nixos"
|
|
NOBARA = "nobara"
|
|
LINUX = "linux"
|
|
LINUXMINT = "linuxmint"
|
|
OPENBSD = "openbsd"
|
|
OPENSUSE = "opensuse"
|
|
POP = "pop"
|
|
PARABOLA = "parabola"
|
|
QUIRINUX = "quirinux"
|
|
RASPBIAN = "raspbian"
|
|
ROCKY = "rocky"
|
|
RHEL = "rhel"
|
|
SIDUCTION = "siduction"
|
|
SLACKWARE = "slackware"
|
|
UBUNTU = "ubuntu"
|
|
UNIVALENT = "univalent"
|
|
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": # pylint: disable=too-many-return-statements
|
|
"""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
|
|
|
|
# Armbian is also detected as _regular_ Debian by `distro`, but going directly
|
|
# through release info gives us a proper id (see <python-distro/distro#366>).
|
|
if distro.distro_release_attr("id") == "armbian":
|
|
return Distributions.ARMBIAN
|
|
|
|
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 `ID` (from `os-release`) well-known and supported ?
|
|
with suppress(ValueError):
|
|
return Distributions(distro.id())
|
|
|
|
# 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(" "):
|
|
with suppress(ValueError):
|
|
return Distributions(id_like)
|
|
|
|
# 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
|