dotfiles/bin/actions/hello.py
Menno van Leeuwen 140863d674
Some checks failed
Ansible Lint Check / check-ansible (push) Failing after 16s
Nix Format Check / check-format (push) Successful in 56s
Python Lint Check / check-python (push) Failing after 16s
feat: add Python linting support with pylint and black
2025-03-12 14:17:43 +01:00

192 lines
6.3 KiB
Python
Executable File

#!/usr/bin/env python3
import os
import sys
import subprocess
from datetime import datetime
# Import helper functions
sys.path.append(os.path.join(os.path.expanduser("~/.dotfiles"), "bin"))
from helpers.functions import printfe, logo, _rainbow_color, COLORS
def get_last_ssh_login():
"""Get information about the last SSH login"""
try:
result = subprocess.run(
["lastlog", "-u", os.environ.get("USER", "")],
capture_output=True,
text=True,
)
# If lastlog didn't work try lastlog2
if result.returncode != 0:
result = subprocess.run(
["lastlog2", os.environ.get("USER", "")], capture_output=True, text=True
)
if result.returncode == 0:
lines = result.stdout.strip().split("\n")
if len(lines) >= 2: # Header line + data line
# Parse the last login line - example format:
# menno ssh 100.99.23.98 Mon Mar 10 19:09:43 +0100 2025
parts = lines[1].split()
if len(parts) >= 7 and "ssh" in parts[1]: # Check if it's an SSH login
# Extract IP address from the third column
ip = parts[2]
# Time is the rest of the line starting from position 3
time_str = " ".join(parts[3:])
return f"{COLORS['cyan']}Last SSH login{COLORS['reset']}{COLORS['yellow']} {time_str}{COLORS['cyan']} from{COLORS['yellow']} {ip}"
return None
except Exception as e:
# For debugging, you might want to print the exception
# print(f"Error getting SSH login: {str(e)}")
return None
def check_dotfiles_status():
"""Check if the dotfiles repository is dirty"""
dotfiles_path = os.environ.get("DOTFILES_PATH", os.path.expanduser("~/.dotfiles"))
try:
if not os.path.isdir(os.path.join(dotfiles_path, ".git")):
return None
# Check for git status details
status = {
"is_dirty": False,
"untracked": 0,
"modified": 0,
"staged": 0,
"commit_hash": "",
"unpushed": 0,
}
# Get status of files
result = subprocess.run(
["git", "status", "--porcelain"],
cwd=dotfiles_path,
capture_output=True,
text=True,
)
if result.stdout.strip():
status["is_dirty"] = True
for line in result.stdout.splitlines():
if line.startswith("??"):
status["untracked"] += 1
if line.startswith(" M") or line.startswith("MM"):
status["modified"] += 1
if line.startswith("M ") or line.startswith("A "):
status["staged"] += 1
# Get current commit hash
result = subprocess.run(
["git", "rev-parse", "--short", "HEAD"],
cwd=dotfiles_path,
capture_output=True,
text=True,
)
if result.returncode == 0:
status["commit_hash"] = result.stdout.strip()
# Count unpushed commits
# Fix: Remove capture_output and set stdout explicitly
result = subprocess.run(
["git", "log", "--oneline", "@{u}.."],
cwd=dotfiles_path,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
text=True,
)
if result.returncode == 0:
status["unpushed"] = len(result.stdout.splitlines())
return status
except Exception as e:
print(f"Error checking dotfiles status: {str(e)}")
return None
def get_condensed_status():
"""Generate a condensed status line for trash and git status"""
status_parts = []
# Check trash status
trash_path = os.path.expanduser("~/.local/share/Trash/files")
try:
if os.path.exists(trash_path):
items = os.listdir(trash_path)
count = len(items)
if count > 0:
status_parts.append(f"[!] {count} file(s) in trash")
except Exception:
pass
# Check dotfiles status
dotfiles_status = check_dotfiles_status()
if dotfiles_status is not None:
if dotfiles_status["is_dirty"]:
status_parts.append(f"{COLORS['yellow']}dotfiles is dirty{COLORS['reset']}")
status_parts.append(
f"{COLORS['red']}[{dotfiles_status['untracked']}] untracked{COLORS['reset']}"
)
status_parts.append(
f"{COLORS['yellow']}[{dotfiles_status['modified']}] modified{COLORS['reset']}"
)
status_parts.append(
f"{COLORS['green']}[{dotfiles_status['staged']}] staged{COLORS['reset']}"
)
if dotfiles_status["commit_hash"]:
status_parts.append(
f"{COLORS['white']}[{COLORS['blue']}{dotfiles_status['commit_hash']}{COLORS['white']}]{COLORS['reset']}"
)
if dotfiles_status["unpushed"] > 0:
status_parts.append(
f"{COLORS['yellow']}[!] You have {dotfiles_status['unpushed']} commit(s) to push{COLORS['reset']}"
)
else:
status_parts.append("Unable to check dotfiles status")
if status_parts:
return " - ".join(status_parts)
return None
def welcome():
"""Display welcome message with hostname and username"""
print()
# Get hostname and username
hostname = os.uname().nodename
username = os.environ.get("USER", os.environ.get("USERNAME", "user"))
# Get SSH login info first
ssh_login = get_last_ssh_login()
print(f"{COLORS['cyan']}You're logged in on [", end="")
print(_rainbow_color(hostname), end="")
print(f"{COLORS['cyan']}] as [", end="")
print(_rainbow_color(username), end="")
print(f"{COLORS['cyan']}]{COLORS['reset']}")
# Display last SSH login info if available
if ssh_login:
print(f"{ssh_login}{COLORS['reset']}")
# Display condensed status line
condensed_status = get_condensed_status()
if condensed_status:
print(f"{COLORS['yellow']}{condensed_status}{COLORS['reset']}")
def main():
logo(continue_after=True)
welcome()
return 0
if __name__ == "__main__":
sys.exit(main())