mirror of
https://github.com/HorlogeSkynet/archey4
synced 2025-04-10 00:00:19 +02:00
[DISTRO] [NEW] Adds (basic) support for Alpine Linux
> Alpine Linux ASCII logo has been borrowed from Neofetch (see <404c955e8f
>).
- Known bug :
- The `Disk` entry is not compatible against the BusyBox `df` implementation.
- Alpine users are advised to **disable** it from configuration.
This commit is contained in:
parent
3ff70faae9
commit
d676b0b2d5
@ -10,6 +10,7 @@ from archey.distributions import Distributions
|
||||
# The first element (`[0]`) of each list will be used to display text entries.
|
||||
COLOR_DICT = {
|
||||
Distributions.ARCH_LINUX: [Colors.CYAN_BRIGHT, Colors.CYAN_NORMAL],
|
||||
Distributions.ALPINE_LINUX: [Colors.BLUE_BRIGHT],
|
||||
Distributions.BUNSENLABS: [Colors.WHITE_BRIGHT, Colors.YELLOW_BRIGHT, Colors.YELLOW_NORMAL],
|
||||
Distributions.CRUNCHBANG: [Colors.WHITE_BRIGHT],
|
||||
Distributions.DEBIAN: [Colors.RED_BRIGHT, Colors.RED_NORMAL],
|
||||
@ -32,6 +33,7 @@ COLOR_DICT = {
|
||||
|
||||
# This dictionary contains which logo should be used for each supported distribution.
|
||||
LOGOS_DICT = {
|
||||
Distributions.ALPINE_LINUX: logos.ALPINE_LINUX,
|
||||
Distributions.ARCH_LINUX: logos.ARCH_LINUX,
|
||||
Distributions.BUNSENLABS: logos.BUNSENLABS,
|
||||
Distributions.CRUNCHBANG: logos.CRUNCHBANG,
|
||||
|
@ -9,6 +9,7 @@ class Distributions(Enum):
|
||||
Values contain their respective `distro` identifier.
|
||||
See <https://distro.readthedocs.io/en/latest/#distro.id>.
|
||||
"""
|
||||
ALPINE_LINUX = 'alpine'
|
||||
ARCH_LINUX = 'arch'
|
||||
BUNSENLABS = 'bunsenlabs'
|
||||
CRUNCHBANG = 'crunchbang'
|
||||
|
@ -11,18 +11,26 @@ from archey.configuration import Configuration
|
||||
class Disk:
|
||||
"""Uses `df` and `btrfs` commands to compute the total disk usage across devices"""
|
||||
def __init__(self):
|
||||
# The configuration object is needed to retrieve some settings below.
|
||||
configuration = Configuration()
|
||||
|
||||
# This dictionary will store values obtained from sub-processes calls.
|
||||
self._usage = {
|
||||
'used': 0.0,
|
||||
'total': 0.0
|
||||
}
|
||||
|
||||
# Fetch the user-defined disk limits from configuration.
|
||||
disk_limits = Configuration().get('limits')['disk']
|
||||
|
||||
self._run_df_usage()
|
||||
self._run_btrfs_usage()
|
||||
|
||||
# Check whether at least one media could be found.
|
||||
if not self._usage['total']:
|
||||
self.value = configuration.get('default_strings')['not_detected']
|
||||
return
|
||||
|
||||
# Fetch the user-defined disk limits from configuration.
|
||||
disk_limits = configuration.get('limits')['disk']
|
||||
|
||||
# Based on the disk percentage usage, select the corresponding level color.
|
||||
level_color = Colors.get_level_color(
|
||||
(self._usage['used'] / (self._usage['total'] or 1)) * 100,
|
||||
@ -56,6 +64,7 @@ class Disk:
|
||||
).splitlines()[-1].split()
|
||||
except CalledProcessError:
|
||||
# It looks like there is not any file system matching our types.
|
||||
# Known bug : `df` available in BusyBox does not support our flags.
|
||||
return
|
||||
|
||||
self._usage['used'] += float(df_output[2].rstrip('MB')) / 1024
|
||||
|
@ -1,11 +1,14 @@
|
||||
"""Number of installed packages detection class"""
|
||||
|
||||
import os
|
||||
|
||||
from subprocess import check_output, DEVNULL, CalledProcessError
|
||||
|
||||
from archey.configuration import Configuration
|
||||
|
||||
|
||||
PACKAGES_TOOLS = (
|
||||
{'cmd': ['apk', 'list', '--installed']},
|
||||
{'cmd': ['apt', 'list', '-qq', '--installed']},
|
||||
{'cmd': ['dnf', 'list', 'installed'], 'skew': 1},
|
||||
{'cmd': ['dpkg', '--get-selections']},
|
||||
@ -25,7 +28,12 @@ class Packages:
|
||||
results = check_output(
|
||||
packages_tool['cmd'],
|
||||
stderr=DEVNULL,
|
||||
env={'LANG': 'C'},
|
||||
env={
|
||||
'LANG': 'C',
|
||||
# Alpine Linux: We have to manually propagate `PATH`.
|
||||
# `apk` wouldn't be found otherwise.
|
||||
'PATH': os.getenv('PATH')
|
||||
},
|
||||
universal_newlines=True
|
||||
)
|
||||
except (FileNotFoundError, CalledProcessError):
|
||||
@ -33,7 +41,7 @@ class Packages:
|
||||
|
||||
packages = results.count('\n')
|
||||
|
||||
# If any, deduct any skew present due to the packages tool output.
|
||||
# If any, deduct output skew present due to the packages tool.
|
||||
if 'skew' in packages_tool:
|
||||
packages -= packages_tool['skew']
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
"""Simple `__init__` file for the `logos` module, to load each distribution logo"""
|
||||
|
||||
from archey.logos.alpine_linux import ALPINE_LINUX
|
||||
from archey.logos.arch_linux import ARCH_LINUX
|
||||
from archey.logos.bunsenlabs import BUNSENLABS
|
||||
from archey.logos.crunchbang import CRUNCHBANG
|
||||
|
24
archey/logos/alpine_linux.py
Normal file
24
archey/logos/alpine_linux.py
Normal file
@ -0,0 +1,24 @@
|
||||
"""Alpine Linux logo"""
|
||||
|
||||
ALPINE_LINUX = """\
|
||||
{c[0]} .hddddddddddddddddddddddh. \n\
|
||||
{c[0]} :dddddddddddddddddddddddddd: {r[0]}
|
||||
{c[0]} /dddddddddddddddddddddddddddd/ {r[1]}
|
||||
{c[0]} +dddddddddddddddddddddddddddddd+ {r[2]}
|
||||
{c[0]} `sdddddddddddddddddddddddddddddddds` {r[3]}
|
||||
{c[0]} `ydddddddddddd++hdddddddddddddddddddy` {r[4]}
|
||||
{c[0]} .hddddddddddd+` `+ddddh:-sdddddddddddh. {r[5]}
|
||||
{c[0]} hdddddddddd+` `+y: .sddddddddddh {r[6]}
|
||||
{c[0]} ddddddddh+` `//` `.` -sddddddddd {r[7]}
|
||||
{c[0]} ddddddh+` `/hddh/` `:s- -sddddddd {r[8]}
|
||||
{c[0]} ddddh+` `/+/dddddh/` `+s- -sddddd {r[9]}
|
||||
{c[0]} ddd+` `/o` :dddddddh/` `oy- .yddd {r[10]}
|
||||
{c[0]} hdddyo+ohddyosdddddddddho+oydddy++ohdddh {r[11]}
|
||||
{c[0]} .hddddddddddddddddddddddddddddddddddddh. {r[12]}
|
||||
{c[0]} `yddddddddddddddddddddddddddddddddddy` {r[13]}
|
||||
{c[0]} `sdddddddddddddddddddddddddddddddds` {r[14]}
|
||||
{c[0]} +dddddddddddddddddddddddddddddd+ {r[15]}
|
||||
{c[0]} /dddddddddddddddddddddddddddd/ {r[16]}
|
||||
{c[0]} :dddddddddddddddddddddddddd: {r[17]}
|
||||
{c[0]} .hddddddddddddddddddddddh. \
|
||||
"""
|
@ -3,7 +3,7 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
from subprocess import check_output
|
||||
from subprocess import CalledProcessError, DEVNULL, check_output
|
||||
|
||||
from archey.singleton import Singleton
|
||||
|
||||
@ -19,9 +19,15 @@ class Processes(metaclass=Singleton):
|
||||
'-o', 'comm',
|
||||
'--no-headers'
|
||||
],
|
||||
universal_newlines=True
|
||||
universal_newlines=True, stderr=DEVNULL
|
||||
).splitlines()
|
||||
|
||||
except CalledProcessError:
|
||||
# The available `ps` implementation may not support passed parameters (hello BusyBox).
|
||||
# Let's fall-back on a much simpler approach.
|
||||
self._processes = check_output(
|
||||
['ps', '-o', 'comm'],
|
||||
universal_newlines=True
|
||||
).splitlines()[1:]
|
||||
except FileNotFoundError:
|
||||
print(
|
||||
"Please, install first `procps` on your distribution.",
|
||||
|
@ -232,6 +232,21 @@ System,RAID1: Size:0.01GiB, Used:0.00GiB
|
||||
disk = Disk().value
|
||||
self.assertTrue(all(i in disk for i in [str(Colors.GREEN_NORMAL), '943.4', '4202.5']))
|
||||
|
||||
@patch(
|
||||
'archey.entries.disk.check_output',
|
||||
side_effect=[
|
||||
CalledProcessError(1, 'df', "df: unrecognized option: l\n"),
|
||||
CalledProcessError(1, 'df', "df: unrecognized option: l\n")
|
||||
]
|
||||
)
|
||||
@patch(
|
||||
'archey.entries.disk.Configuration.get',
|
||||
return_value={'not_detected': 'Not detected'}
|
||||
)
|
||||
def test_df_failing(self, _, __):
|
||||
"""Test df call failing against the BusyBox implementation"""
|
||||
self.assertEqual(Disk().value, 'Not detected')
|
||||
|
||||
@patch(
|
||||
'archey.entries.disk.check_output',
|
||||
side_effect=[
|
||||
@ -241,17 +256,11 @@ System,RAID1: Size:0.01GiB, Used:0.00GiB
|
||||
)
|
||||
@patch(
|
||||
'archey.entries.disk.Configuration.get',
|
||||
return_value={
|
||||
'disk': {
|
||||
'warning': 50,
|
||||
'danger': 75
|
||||
}
|
||||
}
|
||||
return_value={'not_detected': 'Not detected'}
|
||||
)
|
||||
def test_no_recognised_disks(self, _, __):
|
||||
"""Test df failing to detect any valid filesystems"""
|
||||
disk = Disk().value
|
||||
self.assertTrue(all(i in disk for i in [str(Colors.GREEN_NORMAL), '0.0']))
|
||||
"""Test df failing to detect any valid file-systems"""
|
||||
self.assertEqual(Disk().value, 'Not detected')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -15,6 +15,24 @@ class TestPackagesEntry(unittest.TestCase):
|
||||
@patch(
|
||||
'archey.entries.packages.check_output',
|
||||
return_value="""\
|
||||
sqlite-libs-3.30.1-r1 x86_64 {{sqlite}} (Public-Domain) [installed]
|
||||
musl-1.1.24-r2 x86_64 {{musl}} (MIT) [installed]
|
||||
libbz2-1.0.8-r1 x86_64 {{bzip2}} (bzip2-1.0.6) [installed]
|
||||
gdbm-1.13-r1 x86_64 {{gdbm}} (GPL) [installed]
|
||||
ncurses-libs-6.1_p20200118-r3 x86_64 {{ncurses}} (MIT) [installed]
|
||||
zlib-1.2.11-r3 x86_64 {{zlib}} (Zlib) [installed]
|
||||
apk-tools-2.10.4-r3 x86_64 {{apk}-tools} (GPL2) [installed]
|
||||
readline-8.0.1-r0 x86_64 {{readline}} (GPL-2.0-or-later) [installed]
|
||||
""")
|
||||
def test_match_with_apk(self, _):
|
||||
"""Simple test for the APK packages manager"""
|
||||
self.assertEqual(Packages().value, 8)
|
||||
|
||||
@patch(
|
||||
'archey.entries.packages.check_output',
|
||||
side_effect=[
|
||||
FileNotFoundError(),
|
||||
"""\
|
||||
accountsservice/stable,now 0.6.45-2 amd64 [installed,automatic]
|
||||
acl/stable,now 2.2.53-4 amd64 [installed,automatic]
|
||||
adb/stable,now 1:8.1.0+r23-5 amd64 [installed]
|
||||
@ -22,7 +40,7 @@ adduser/stable,now 3.118 all [installed]
|
||||
adwaita-icon-theme/stable,now 3.30.1-1 all [installed,automatic]
|
||||
albatross-gtk-theme/stable,now 1.7.4-1 all [installed,automatic]
|
||||
alsa-utils/stable,now 1.1.8-2 amd64 [installed,automatic]
|
||||
""")
|
||||
"""])
|
||||
def test_match_with_apt(self, _):
|
||||
"""Simple test for the APT packages manager"""
|
||||
self.assertEqual(Packages().value, 7)
|
||||
@ -30,6 +48,7 @@ alsa-utils/stable,now 1.1.8-2 amd64 [installed,automatic]
|
||||
@patch(
|
||||
'archey.entries.packages.check_output',
|
||||
side_effect=[
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
"""\
|
||||
Installed Packages
|
||||
@ -45,6 +64,7 @@ GraphicsMagick.x86_64 1.3.26-3.fc26 @@commandline
|
||||
@patch(
|
||||
'archey.entries.packages.check_output',
|
||||
side_effect=[
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
"""\
|
||||
@ -66,6 +86,7 @@ alien install
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
"""\
|
||||
|
||||
These are the packages that would be merged, in order:
|
||||
@ -90,6 +111,7 @@ USE="pam -static-libs" ABI_X86="(64) -32 (-x32)" \n\
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
"""\
|
||||
acl 2.2.52-4
|
||||
archey4 v4.3.3-1
|
||||
@ -108,6 +130,7 @@ argon2 20171227-3
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
"""\
|
||||
cdrecord-2.01-10.7.el5
|
||||
bluez-libs-3.7-1.1
|
||||
@ -127,6 +150,7 @@ MySQL-client-3.23.57-1
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
"""\
|
||||
Loaded plugins: fastestmirror, langpacks
|
||||
Installed Packages
|
||||
@ -149,6 +173,7 @@ ModemManager-glib.x86_64 1.6.0-2.el7 @base \n\
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
"""\
|
||||
Loading repository data...
|
||||
Reading installed packages...
|
||||
@ -175,6 +200,7 @@ i | at | A Job Manager | package \n\
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError(),
|
||||
FileNotFoundError()
|
||||
]
|
||||
)
|
||||
|
@ -1,5 +1,7 @@
|
||||
"""Test module for `archey.processes`"""
|
||||
|
||||
from subprocess import CalledProcessError
|
||||
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
@ -34,7 +36,7 @@ there
|
||||
processes_1 = Processes()
|
||||
_ = Processes()
|
||||
|
||||
self.assertEqual(
|
||||
self.assertListEqual(
|
||||
processes_1.get(),
|
||||
['what', 'an', 'awesome', 'processes', 'list', 'you', 'got', 'there']
|
||||
)
|
||||
@ -43,6 +45,27 @@ there
|
||||
# `unittest.mock.Mock.assert_called_once` is not available against Python < 3.6.
|
||||
self.assertEqual(check_output_mock.call_count, 1)
|
||||
|
||||
@patch.dict(
|
||||
'archey.singleton.Singleton._instances',
|
||||
clear=True
|
||||
)
|
||||
@patch(
|
||||
'archey.processes.check_output',
|
||||
side_effect=[
|
||||
CalledProcessError(1, 'ps', "ps: unrecognized option: u\n"),
|
||||
"""\
|
||||
COMMAND
|
||||
sh
|
||||
top
|
||||
ps
|
||||
"""])
|
||||
def test_ps_failed(self, _):
|
||||
"""Verifies that the program correctly handles first crashing `ps` call"""
|
||||
self.assertListEqual(
|
||||
Processes().get(),
|
||||
['sh', 'top', 'ps']
|
||||
)
|
||||
|
||||
@patch.dict(
|
||||
'archey.singleton.Singleton._instances',
|
||||
clear=True
|
||||
|
Loading…
x
Reference in New Issue
Block a user