dotfiles/welcome/main.py

273 lines
6.9 KiB
Python
Raw Normal View History

2018-08-08 08:35:35 +00:00
import os
import platform
2018-08-08 20:08:05 +00:00
import re
2018-08-08 08:35:35 +00:00
import socket
from datetime import datetime, timedelta
from getpass import getuser
2018-08-08 20:08:05 +00:00
2018-08-08 08:35:35 +00:00
import psutil
2018-08-08 20:08:05 +00:00
from colorama import Fore, Style, ansi
2018-08-08 08:35:35 +00:00
COLORS = [ansi.code_to_chars(30 + color_index) for color_index in range(0, 8)]
def colored(string, *colors):
2018-08-08 18:16:26 +00:00
return "".join(colors + (string, Style.RESET_ALL))
2018-08-08 08:35:35 +00:00
def bright_colored(string, *colors):
2018-08-08 18:16:26 +00:00
return "".join(colors + (Style.BRIGHT, string, Style.RESET_ALL))
2018-08-08 08:35:35 +00:00
def format_timedelta(timedelta):
2018-08-08 18:16:26 +00:00
result = []
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
days = timedelta.days
mm, ss = divmod(timedelta.seconds, 60)
hh, mm = divmod(mm, 60)
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
def plural(n):
return n, "s" if abs(n) != 1 else ""
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
if days > 0:
result.append("%d day%s" % plural(days))
if hh > 0 or result:
result.append("%d hour%s" % plural(hh))
if mm > 0 or result:
result.append("%d min%s" % plural(mm))
if len(result) <= 1:
result.append("%d sec%s" % plural(ss))
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
return ", ".join(result)
2018-08-08 08:35:35 +00:00
def humanize_bytes(bytes):
2018-08-08 18:16:26 +00:00
units = ["B", "kB", "MB", "GB"]
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
factor = 1
2018-08-08 20:08:05 +00:00
for _unit in units:
2018-08-08 18:16:26 +00:00
next_factor = factor << 10
if bytes < next_factor:
break
factor = next_factor
2018-08-08 08:35:35 +00:00
2018-08-08 20:08:05 +00:00
return "%.2f %s" % (float(bytes) / factor, _unit)
2018-08-08 08:35:35 +00:00
def colorize_percent(percent, warning, critical, inverse=False):
2018-08-08 18:16:26 +00:00
COLORS = [Fore.GREEN, Fore.YELLOW, Fore.RED]
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
color_index = 0 if percent < warning else 1 if percent < critical else 2
if inverse:
color_index = 2 - color_index
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
return colored("%.2f%%" % percent, COLORS[color_index])
2018-08-08 08:35:35 +00:00
def get_hostname():
2018-08-08 18:16:26 +00:00
hostname = socket.gethostname()
local_ip = socket.gethostbyname(hostname)
return hostname, local_ip
2018-08-08 08:35:35 +00:00
def uptime():
2018-08-08 18:16:26 +00:00
return datetime.now() - datetime.fromtimestamp(psutil.boot_time())
2018-08-08 08:35:35 +00:00
def users():
2018-08-08 18:16:26 +00:00
users = {}
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
for user in psutil.users():
name = user.name
terminal = user.terminal
if name in users:
users[name].append(terminal)
else:
users[name] = [terminal]
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
result = []
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
for name in users:
terminals = users[name]
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
colored_name = bright_colored(name, Fore.BLUE)
colored_terminals = [
colored(term, Style.BRIGHT, Fore.BLACK) for term in terminals
]
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
terminals_str = ", ".join(colored_terminals)
if len(colored_terminals) > 1:
terminals_str = "(%s)" % terminals_str
result.append(colored_name + "@" + terminals_str)
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
return ", ".join(result)
2018-08-08 08:35:35 +00:00
def shell():
2018-08-08 18:16:26 +00:00
return os.environ["SHELL"]
2018-08-08 08:35:35 +00:00
def cpu_usage():
2018-08-08 18:16:26 +00:00
percent = psutil.cpu_percent()
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
return colorize_percent(percent, warning=60, critical=80)
2018-08-08 08:35:35 +00:00
def memory():
2018-08-08 18:16:26 +00:00
memory = psutil.virtual_memory()
return (
humanize_bytes(memory.used),
humanize_bytes(memory.total),
colorize_percent(memory.percent, warning=60, critical=80),
)
2018-08-08 08:35:35 +00:00
def disks():
2018-08-08 18:16:26 +00:00
result = []
for disk in psutil.disk_partitions(all=False):
if psutil.WINDOWS and ("cdrom" in disk.opts or disk.fstype == ""):
2018-08-08 20:08:05 +00:00
# skip cd-rom drives with no disk in it on Windows; they may raise
# ENOENT, pop-up a Windows GUI error for a non-ready partition or
# just hang
2018-08-08 18:16:26 +00:00
continue
usage = psutil.disk_usage(disk.mountpoint)
result.append(
(
disk.mountpoint,
humanize_bytes(usage.used),
humanize_bytes(usage.total),
colorize_percent(usage.percent, warning=70, critical=85),
)
)
return result
2018-08-08 08:35:35 +00:00
def battery():
2018-08-08 18:16:26 +00:00
if not hasattr(psutil, "sensors_battery"):
return None
2018-08-08 08:39:04 +00:00
2018-08-08 18:16:26 +00:00
try:
battery = psutil.sensors_battery()
except Exception as e:
print(e)
return None
2018-08-08 08:39:04 +00:00
2018-08-08 18:16:26 +00:00
if battery is None:
return None
2018-08-08 08:39:04 +00:00
2018-08-08 18:16:26 +00:00
percent = battery.percent
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
if battery.power_plugged:
status = "charging" if percent < 100 else "fully charged"
else:
status = "%s left" % format_timedelta(timedelta(seconds=battery.secsleft))
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
return colorize_percent(percent, critical=10, warning=20, inverse=True), status
2018-08-08 08:35:35 +00:00
2018-08-08 09:08:22 +00:00
def is_android():
2018-08-08 18:16:26 +00:00
return os.path.isdir("/system/app") and os.path.isdir("/system/priv-app")
2018-08-08 09:08:22 +00:00
2018-08-08 08:35:35 +00:00
def get_distro_info():
2018-08-08 18:16:26 +00:00
if psutil.WINDOWS:
return "windows", platform.system(), platform.release(), ""
elif psutil.OSX:
from plistlib import readPlist
sw_vers = readPlist("/System/Library/CoreServices/SystemVersion.plist")
return "mac", sw_vers["ProductName"], sw_vers["ProductVersion"], ""
elif is_android():
from subprocess import check_output
android_version = check_output(["getprop", "ro.build.version.release"])
return "android", "Android", android_version.decode().strip(), ""
elif psutil.LINUX:
import distro
return distro.id(), distro.name(), distro.version(), distro.codename()
2018-08-08 20:08:05 +00:00
raise NotImplementedError("unsupported OS")
2018-08-08 08:35:35 +00:00
def get_system_info():
2018-08-08 18:16:26 +00:00
info_lines = []
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
def info(name, value, *format_args):
line = colored(name + ":", Style.BRIGHT, Fore.YELLOW) + " " + value
if format_args:
line = line % format_args
info_lines.append(line)
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
username = getuser()
hostname, local_ip = get_hostname()
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
info_lines.append(
bright_colored(username, Fore.BLUE) + "@" + bright_colored(hostname, Fore.RED)
)
info_lines.append("")
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
distro_id, distro_name, distro_version, distro_codename = get_distro_info()
info("OS", " ".join([distro_name, distro_version, distro_codename]))
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
logo_path = os.path.join(os.path.dirname(__file__), "logos", distro_id)
with open(logo_path) as logo_file:
logo_lines = logo_file.read().splitlines()
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
info("Kernel", "%s %s", platform.system(), platform.release())
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
info("Uptime", format_timedelta(uptime()))
2018-08-08 09:46:32 +00:00
2018-08-08 18:16:26 +00:00
users_info = users()
if users_info:
info("Users", users_info)
2018-08-08 09:46:32 +00:00
2018-08-08 18:16:26 +00:00
info("Shell", shell())
2018-08-08 09:46:32 +00:00
2018-08-08 18:16:26 +00:00
info("IP address", local_ip)
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
info_lines.append("")
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
info("CPU Usage", "%s", cpu_usage())
info("Memory", "%s / %s (%s)", *memory())
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
for disk_info in disks():
info("Disk (%s)", "%s / %s (%s)", *disk_info)
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
battery_info = battery()
if battery_info is not None:
info("Battery", "%s (%s)", *battery_info)
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
return logo_lines, info_lines
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
print("")
2018-08-08 08:35:35 +00:00
logo_lines, info_lines = get_system_info()
2018-08-08 18:16:26 +00:00
logo_line_widths = [len(re.sub(r"{\d}", "", line)) for line in logo_lines]
2018-08-08 08:35:35 +00:00
logo_width = max(logo_line_widths)
for line_index in range(0, max(len(logo_lines), len(info_lines))):
2018-08-08 18:16:26 +00:00
line = ""
logo_line_width = 0
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
if line_index < len(logo_lines):
logo_line = logo_lines[line_index]
logo_line_width = logo_line_widths[line_index]
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
line += Style.BRIGHT
line += logo_line.format(*COLORS)
line += Style.RESET_ALL
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
line += " " * (logo_width - logo_line_width + 3)
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
if line_index < len(info_lines):
info_line = info_lines[line_index]
line += info_line
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
print(line)
2018-08-08 08:35:35 +00:00
2018-08-08 18:16:26 +00:00
print("")