192 lines
6.3 KiB
Python
Executable File
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())
|