Source code for extra_platforms.detection

# Copyright Kevin Deldycke <kevin@deldycke.com> and contributors.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
"""Heuristics to detect each platform.

All these heuristics can be hard-cached as the underlying system is not changing
between code execution.

We mostly rely on `distro <https://github.com/python-distro/distro>`_ to detect the
Linux distribution, as it is the recommended replacement for Python's original
``platform.linux_distribution`` function (which was removed in Python 3.8).

We then fill in the gaps with ``sys.platform`` and environment variables to detect
systems not covered by ``distro``.

This collection of heuristics is designed as a set of separate function with minimal
logic and dependencies. That way we can double-check during execution that no
heuristics are conflicting or matching multiple systems at the same time.

.. note::

    Heuristics for unrecognized platforms can be transplanted from `Rust's sysinfo
    crate <https://github.com/stanislav-tkach/os_info/tree/master/os_info/src>`_.
"""

from __future__ import annotations

import logging
import platform
import sys
from os import environ

import distro

from . import cache


[docs] @cache def is_aix() -> bool: """Return `True` only if current platform is AIX.""" return sys.platform.startswith("aix") or distro.id() == "aix"
[docs] @cache def is_altlinux() -> bool: """Return `True` only if current platform is ALT Linux.""" return distro.id() == "altlinux"
[docs] @cache def is_amzn() -> bool: """Return `True` only if current platform is Amazon Linux.""" return distro.id() == "amzn"
[docs] @cache def is_android() -> bool: """Return `True` only if current platform is Android. Source: https://github.com/kivy/kivy/blob/master/kivy/utils.py#L429 """ return "ANDROID_ROOT" in environ or "P4A_BOOTSTRAP" in environ
[docs] @cache def is_arch() -> bool: """Return `True` only if current platform is Arch Linux.""" return distro.id() == "arch"
[docs] @cache def is_buildroot() -> bool: """Return `True` only if current platform is Buildroot.""" return distro.id() == "buildroot"
[docs] @cache def is_centos() -> bool: """Return `True` only if current platform is CentOS.""" return distro.id() == "centos"
[docs] @cache def is_cloudlinux() -> bool: """Return `True` only if current platform is CloudLinux OS.""" return distro.id() == "cloudlinux"
[docs] @cache def is_cygwin() -> bool: """Return `True` only if current platform is Cygwin.""" return sys.platform.startswith("cygwin")
[docs] @cache def is_debian() -> bool: """Return `True` only if current platform is Debian.""" return distro.id() == "debian"
[docs] @cache def is_exherbo() -> bool: """Return `True` only if current platform is Exherbo Linux.""" return distro.id() == "exherbo"
[docs] @cache def is_fedora() -> bool: """Return `True` only if current platform is Fedora.""" return distro.id() == "fedora"
[docs] @cache def is_freebsd() -> bool: """Return `True` only if current platform is FreeBSD.""" return sys.platform.startswith("freebsd") or distro.id() == "freebsd"
[docs] @cache def is_gentoo() -> bool: """Return `True` only if current platform is GenToo Linux.""" return distro.id() == "gentoo"
[docs] @cache def is_guix() -> bool: """Return `True` only if current platform is Guix System.""" return distro.id() == "guix"
[docs] @cache def is_hurd() -> bool: """Return `True` only if current platform is GNU/Hurd.""" return sys.platform.startswith("GNU")
[docs] @cache def is_ibm_powerkvm() -> bool: """Return `True` only if current platform is IBM PowerKVM.""" return distro.id() == "ibm_powerkvm"
[docs] @cache def is_kvmibm() -> bool: """Return `True` only if current platform is KVM for IBM z Systems.""" return distro.id() == "kvmibm"
[docs] @cache def is_linuxmint() -> bool: """Return `True` only if current platform is Linux Mint.""" return distro.id() == "linuxmint"
[docs] @cache def is_macos() -> bool: """Return `True` only if current platform is macOS.""" return platform.platform(terse=True).startswith(("macOS", "Darwin"))
[docs] @cache def is_mageia() -> bool: """Return `True` only if current platform is Mageia.""" return distro.id() == "mageia"
[docs] @cache def is_mandriva() -> bool: """Return `True` only if current platform is Mandriva Linux.""" return distro.id() == "mandriva"
[docs] @cache def is_midnightbsd() -> bool: """Return `True` only if current platform is MidnightBSD.""" return sys.platform.startswith("midnightbsd") or distro.id() == "midnightbsd"
[docs] @cache def is_netbsd() -> bool: """Return `True` only if current platform is NetBSD.""" return sys.platform.startswith("netbsd") or distro.id() == "netbsd"
[docs] @cache def is_openbsd() -> bool: """Return `True` only if current platform is OpenBSD.""" return sys.platform.startswith("openbsd") or distro.id() == "openbsd"
[docs] @cache def is_opensuse() -> bool: """Return `True` only if current platform is openSUSE.""" return distro.id() == "opensuse"
[docs] @cache def is_oracle() -> bool: """Return `True` only if current platform is Oracle Linux (and Oracle Enterprise Linux).""" return distro.id() == "oracle"
[docs] @cache def is_parallels() -> bool: """Return `True` only if current platform is Parallels.""" return distro.id() == "parallels"
[docs] @cache def is_pidora() -> bool: """Return `True` only if current platform is Pidora.""" return distro.id() == "pidora"
[docs] @cache def is_raspbian() -> bool: """Return `True` only if current platform is Raspbian.""" return distro.id() == "raspbian"
[docs] @cache def is_rhel() -> bool: """Return `True` only if current platform is RedHat Enterprise Linux.""" return distro.id() == "rhel"
[docs] @cache def is_rocky() -> bool: """Return `True` only if current platform is Rocky Linux.""" return distro.id() == "rocky"
[docs] @cache def is_scientific() -> bool: """Return `True` only if current platform is Scientific Linux.""" return distro.id() == "scientific"
[docs] @cache def is_slackware() -> bool: """Return `True` only if current platform is Slackware.""" return distro.id() == "slackware"
[docs] @cache def is_sles() -> bool: """Return `True` only if current platform is SUSE Linux Enterprise Server.""" return distro.id() == "sles"
[docs] @cache def is_solaris() -> bool: """Return `True` only if current platform is Solaris.""" return platform.platform(aliased=True, terse=True).startswith("Solaris")
[docs] @cache def is_sunos() -> bool: """Return `True` only if current platform is SunOS.""" return platform.platform(aliased=True, terse=True).startswith("SunOS")
[docs] @cache def is_ubuntu() -> bool: """Return `True` only if current platform is Ubuntu.""" return distro.id() == "ubuntu"
[docs] @cache def is_unknown_linux() -> bool: """Return `True` only if current platform is an unknown Linux. Excludes WSL1 and WSL2 from this check to `avoid false positives <https://github.com/kdeldycke/meta-package-manager/issues/944>`_. """ unknown_linux = sys.platform.startswith("linux") and not ( is_altlinux() or is_amzn() or is_android() or is_arch() or is_buildroot() or is_centos() or is_cloudlinux() or is_debian() or is_exherbo() or is_fedora() or is_gentoo() or is_guix() or is_ibm_powerkvm() or is_kvmibm() or is_linuxmint() or is_mageia() or is_mandriva() or is_opensuse() or is_oracle() or is_parallels() or is_pidora() or is_raspbian() or is_rhel() or is_rocky() or is_scientific() or is_slackware() or is_sles() or is_ubuntu() or is_xenserver() or is_wsl1() or is_wsl2() ) if unknown_linux: logging.warning( f"Unknow Linux detected: {distro.info()!r}. You can report this warning to" " the extra-platforms project to improve detection heuristics." ) return unknown_linux
[docs] @cache def is_windows() -> bool: """Return `True` only if current platform is Windows.""" return sys.platform.startswith("win32")
[docs] @cache def is_wsl1() -> bool: """Return `True` only if current platform is Windows Subsystem for Linux v1. .. caution:: The only difference between WSL1 and WSL2 is `the case of the kernel release version <https://github.com/andweeb/presence.nvim/pull/64#issue-1174430662>`_: - WSL 1: .. code-block:: shell-session $ uname -r 4.4.0-22572-Microsoft - WSL 2: .. code-block:: shell-session $ uname -r 5.10.102.1-microsoft-standard-WSL2 """ return "Microsoft" in platform.release()
[docs] @cache def is_wsl2() -> bool: """Return `True` only if current platform is Windows Subsystem for Linux v2.""" return "microsoft" in platform.release()
[docs] @cache def is_xenserver() -> bool: """Return `True` only if current platform is XenServer.""" return distro.id() == "xenserver"