Пишем клон neofetch на python
Table of Contents
Немного о самой программе
Думаю, что каждому пользователю UNIX-подобных систем знакома утилита neofetch и её аналоги (pfetch,screenfetch и некоторые другие). Эта маленькая программа позволяет вывести информацию о системе и аппаратной части компьютера в удобном формате.
Neofetch есть в большинстве дистрибутивов, (и даже есть возможность установки в windows и haiku), да и собрать из исходников никто не мешает.
K примеру в ubuntu она ставиться следующим образом:
sudo apt update
sudo apt install neofetch
На гифке выше - neofetch выводит название ОС, имя хоста, shell, разрешение экрана, оконный менеджер, gtk тему, иконки и название терминала. Чуть ниже расположена полоска с цветами, отображающая цветовую схему терминала. Однако можно вывести куда больше информации, и на этом этапе вы можете начать разбираться с конфигурационным файлом. Как правило он лежит в директории ~/.config/neofetch . Если такой директории нет, то создайте её и в ней пропишите конфиг в файле config.conf.
vim ~ /.config/neofetch/config.conf
Однако мне захотелось сделать свою версию на python. И для начала я отправился на github и нашёл там уже готовое решение,правда для MacOs. И естественно оно не заработало на linux, даже не смотря то, что это схожие системы с точки зрения UNIX. И потому было принято решение переписать эту программу.
Я не стал менять архитектуру скрипта, а просто изменил системные вызовы , подходящиe для linux систем.
Модули
Локальный ip адрес
Давайте определим локальный ip адрес. Сделаем мы это при помощи модуля socket.
Создаём функцию local_ip, ищем локальный адрес, открывая localhost и перебирая порты. Функция сохраняет значение, которые в последствии мы выведем пользователю на экран. Если же по каким-то причинам нам это не удалось, то функция сохраняет значение None.
По такому же принципу работают и остальные модули, которые обозначены ниже.
def local_ip():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
return s.getsockname()[0]
except:
return None
Имя хоста
В функции host_name через socket.gethostname() определяем имя хоста.
def host_name():
try:
return socket.gethostname()
except:
return None
Операционная система
Чтобы определить операционную систему воспользуемся специальной библиотекой - platform.
def os_version():
try:
return platform.linux_distribution(distname='', version='', id='', supported_dists=('SuSE', 'debian', 'redhat', 'mandrake', ...), full_distribution_name=1)
except:
return None
Разрешение экрана
Давайте теперь узнаем разрешение экрана. Сделаем мы это при помощи библиотеки subprocess, которой мы воспользуемся ещё не раз. Главным для нас являтся subprocess.check_output , который позволяет прямо из python выполнять команды sh. Чтобы выяснить разрешение в терминале можно ввести команду :
xrandr
А в своём python скрипте мы напишем следущее:
def screen_size():
try:
return subprocess.check_output(["xrandr | grep \"*\""], shell=True)
except:
return None
Однако в выводе терминала мы получаем следущее
b' 1280x1024 60.02*+ 75.02 \n'
На мой взгляд это выглядит некрасиво. Потому давайте поправим эту ситуацию. Мы просто декодируем вывод в удобо-читаемый формат.
.decode('utf-8')
Итоговая конструкции выглядит следующим образом:
def screen_size():
try:
return subprocess.check_output(["xrandr | grep \"*\""], shell=True).decode('utf-8')
except:
return None
Uptime
Через тот же модуль узнаем uptime - время проведённое за текущей сессией. Команда uptime выведет нам крайне много информации, которая на мой взгляд лишняя. Потому я добавил префикс -p , что является сокращением от pretty. Основываясь на опыте написания предыдущего модуля, добавляем .decode(‘utf-8’).
def uptime():
try:
return subprocess.check_output(["uptime -p"], shell=True).decode('utf-8')
except:
return None
Shell
Название shell узнаем при помощи библиотеки os.
def shell():
try:
return os.environ.get('SHELL', '')
except:
return None
Ядро
Версию ядра можно вывести при помощи platform - библиотеки,которая может нам рассказать много интересного об установленном билде python, платформе на которую установлен язык. Также эта библиотека может показать нам версию ядра, и неважно будет оно “ванильным” или пропатченным каким-либо мейнтейнером.
def kernel():
try:
return platform.release()
except:
return None
Архитектура процессора
Скажу честно, адекватно выводить название процессора и его поколение я не научился (я работаю над этим). Однако без каких-либо проблем я могу выводить название архитектуры процессора. Так как в наличии у меня только компьютер с архитектурой x86_64, то и тестировалась эта функция на предмет вывода x86_64. Если у вас есть устройства на базе других архитектур: arm, powerpc и прочих, то прошу вас протестировать. В случае проблем откройте тикет на github в соотвествующем репозитории.
def cpu_spec():
try:
return platform.processor()
except:
return None
DE/WM
Теперь выведем Desktop environment(DE) и window manager(WM). os.environ.get() позволит нам узнать, что же у нас за окружение.
def de():
try:
return os.environ.get('DESKTOP_SESSION')
except:
return None
Шаблон
Теперь самое вкусное - шаблон. Здесь в виде ascii мы нарисуем пингвинчика Tux - символа linux, гапсы для вывода информации,которыю мы собирали модулями, а также цветовую палитру.
Создаём константу TEMPLATE в которой мы выводим информацию на экран. Однако вы зададитесь вопросом, что за \033[92m . А я вам отвечу - это комманда позволяющая окрашивать терминал в различные цвета. Она работает и без python, можете попробовать её в своём терминале. Её используют для проверки цветового покрытия терминала . Можете почитать об этом подробнее тут .
TEMPLATE = """
\033[92m a88888. {hostname} \033[0m
\033[92m d888888b. \033[0m {hostname_sep}
\033[92m d888888b. \033[0m\033[93m OS: {os_version}
\033[92m 8P"YP"Y88 \033[0m\033[93m Kernel:{kernel}
\033[93m 8|o||o|88 \033[0m\033[93m Cpu architecture: {cpu}
\033[93m 8' .88 \033[0m\033[93m Shell: {shell}
\033[93m 8' .88 \033[0m\033[93m DE(WM): {de}
\033[93m 8`._.' Y8 \033[0m\033[93m Uptime: {uptime}
\033[91m d/ `8b. \033[0m\033[93m Resolution: {size}
\033[91m .dP . Y8b\033[0m\033[93m Local IP: {local_ip}
\033[91m d8:' " `::88b.
\033[95m d8" `Y88b
\033[95m :8P ' :888
\033[95m 8a. : _a88
\033[94m ._/"Yaa_ : .| 88P|
\033[94m \ YP" `| 8P `.
\033[94m / \._____.d| .'
\033[94m `--..__)888888P`._.'
\033[30m███\033[0m\033[91m███\033[0m\033[92m███\033[0m\033[93m███\033[0m\033[94m███\033[0m\033[95m███\033[0m\033[96m███\0
"""
Вывод информации
Ну и на последок нам стоит привести выше изложенный template в работоспособное состояние. Просто обозначаем команду вывода в которой указываем что хотим вывести - сохранённые значения функций и сепаратор.
print(TEMPLATE.format(hostname = host_name(),
hostname_sep = "-" * len(host_name()),
os_version=os_version(),
kernel=kernel(),
cpu=cpu_spec(),
shell=shell(),
de=de(),
uptime=uptime(),
size=screen_size(),
local_ip=local_ip()
))
И что в итоге?
Сохранив скрипт и запустив его, мы получаем следующий результат:
Ну и по традиции прилагаю репозиторий на GitHub’е .