feat: remove deprecated shell scripts and add Python alternatives for all of them
Some checks failed
Nix Format Check / check-format (push) Failing after 37s

This commit is contained in:
2025-03-10 15:48:33 +01:00
parent a1e145871b
commit 62954eb986
17 changed files with 652 additions and 641 deletions

97
bin/helpers/functions.py Normal file
View File

@ -0,0 +1,97 @@
#!/usr/bin/env python3
import os
import sys
import subprocess
import math
import random
try:
import pyfiglet
except ImportError:
pyfiglet = None
# Color codes for terminal output
COLORS = {
"black": "\033[0;30m",
"red": "\033[0;31m",
"green": "\033[0;32m",
"yellow": "\033[0;33m",
"blue": "\033[0;34m",
"purple": "\033[0;35m",
"cyan": "\033[0;36m",
"white": "\033[0;37m",
"reset": "\033[0m"
}
def printfe(color, message):
"""Print a formatted message with the specified color"""
color_code = COLORS.get(color.lower(), COLORS["reset"])
print(f"{color_code}{message}{COLORS['reset']}")
def println(message, color=None):
"""Print a line with optional color"""
if color:
printfe(color, message)
else:
print(message)
def _rainbow_color(text, freq=0.1, offset=0):
"""Apply rainbow colors to text similar to lolcat"""
colored_text = ""
for i, char in enumerate(text):
if char.strip(): # Only color non-whitespace characters
# Calculate RGB values using sine waves with phase shifts
r = int(127 * math.sin(freq * i + offset + 0) + 128)
g = int(127 * math.sin(freq * i + offset + 2 * math.pi / 3) + 128)
b = int(127 * math.sin(freq * i + offset + 4 * math.pi / 3) + 128)
# Apply the RGB color to the character
colored_text += f"\033[38;2;{r};{g};{b}m{char}\033[0m"
else:
colored_text += char
return colored_text
def logo(continue_after=False):
"""Display the dotfiles logo"""
try:
# Try to read logo file first for backward compatibility
logo_path = f"{os.environ.get('DOTFILES_PATH', os.path.expanduser('~/.dotfiles'))}/bin/resources/logo.txt"
if os.path.exists(logo_path):
with open(logo_path, "r") as f:
logo_text = f.read()
print(logo_text)
elif pyfiglet:
# Generate ASCII art with pyfiglet and rainbow colors
ascii_art = pyfiglet.figlet_format("Menno's Dotfiles", font='slant')
print("\n") # Add some space before the logo
# Use a random offset to vary the rainbow start position
random_offset = random.random() * 2 * math.pi
line_offset = 0
for line in ascii_art.splitlines():
# Add a little variation to each line
print(_rainbow_color(line, offset=random_offset + line_offset))
line_offset += 0.1
print("\n") # Add some space after the logo
else:
# Fallback if pyfiglet is not available
printfe("yellow", "\n\n *** Menno's Dotfiles ***\n\n")
printfe("cyan", " Note: Install pyfiglet for better logo display")
printfe("cyan", " (pip install pyfiglet)\n")
if not continue_after:
sys.exit(0)
except Exception as e:
printfe("red", f"Error displaying logo: {e}")
def run_command(command, shell=False):
"""Run a shell command and return the result"""
try:
result = subprocess.run(command, shell=shell, check=True, text=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return True, result.stdout.strip()
except subprocess.CalledProcessError as e:
return False, e.stderr.strip()

View File

@ -1,262 +0,0 @@
#!/usr/bin/env bash
#Color print function, usage: println "message" "color"
println() {
color=$2
printfe "%s\n" $color "$1"
}
is_wsl() {
if [ -f "/proc/sys/fs/binfmt_misc/WSLInterop" ]; then
return 0
else
return 1
fi
}
logo() {
echo "Menno's Dotfiles" | figlet | lolcat
if [[ $(trash-list | wc -l) -gt 0 ]]; then
printfe "%s" "yellow" "[!] $(trash-list | wc -l | tr -d ' ') file(s) in trash - "
fi
# Print if repo is dirty and the count of untracked files, modified files and staged files
if [[ $(git -C $DOTFILES_PATH status --porcelain) ]]; then
printfe "%s" "yellow" "dotfiles is dirty "
printfe "%s" "red" "[$(git -C $DOTFILES_PATH status --porcelain | grep -c '^??')] untracked "
printfe "%s" "yellow" "[$(git -C $DOTFILES_PATH status --porcelain | grep -c '^ M')] modified "
printfe "%s" "green" "[$(git -C $DOTFILES_PATH status --porcelain | grep -c '^M ')] staged "
fi
printfe "%s" "blue" "[$(git -C $DOTFILES_PATH rev-parse --short HEAD)] "
if [[ $(git -C $DOTFILES_PATH log origin/master..HEAD) ]]; then
printfe "%s" "yellow" "[!] You have $(git -C $DOTFILES_PATH log origin/master..HEAD --oneline | wc -l | tr -d ' ') commit(s) to push"
fi
println "" "normal"
}
# print colored with printf (args: format, color, message ...)
printfe() {
format=$1
color=$2
shift 2
red=$(tput setaf 1)
green=$(tput setaf 2)
yellow=$(tput setaf 3)
blue=$(tput setaf 4)
magenta=$(tput setaf 5)
cyan=$(tput setaf 6)
normal=$(tput sgr0)
case $color in
"red")
color=$red
;;
"green")
color=$green
;;
"yellow")
color=$yellow
;;
"blue")
color=$blue
;;
"magenta")
color=$magenta
;;
"cyan")
color=$cyan
;;
*)
color=$normal
;;
esac
printf "$color$format$normal" "$@"
}
ensure_package_installed() {
if ! command -v $1 &>/dev/null; then
println "$1 is not installed. Please install it." "red"
exit 1
fi
println " - $1 is available." "green"
}
ensure_sudo_privileges() {
if sudo -n true 2>/dev/null; then
return
else
println "$1" "yellow"
sudo true
fi
}
function exesudo ()
{
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##
#
# LOCAL VARIABLES:
#
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##
#
# I use underscores to remember it's been passed
local _funcname_="$1"
local params=( "$@" ) ## array containing all params passed here
local tmpfile="/dev/shm/$RANDOM" ## temporary file
local content ## content of the temporary file
local regex ## regular expression
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##
#
# MAIN CODE:
#
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##
#
# WORKING ON PARAMS:
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Shift the first param (which is the name of the function)
unset params[0] ## remove first element
# params=( "${params[@]}" ) ## repack array
#
# WORKING ON THE TEMPORARY FILE:
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
content="#!/bin/bash\n\n"
#
# Write the params array
content="${content}params=(\n"
regex="\s+"
for param in "${params[@]}"
do
if [[ "$param" =~ $regex ]]
then
content="${content}\t\"${param}\"\n"
else
content="${content}\t${param}\n"
fi
done
content="$content)\n"
echo -e "$content" > "$tmpfile"
#
# Append the function source
echo "#$( type "$_funcname_" )" >> "$tmpfile"
#
# Append the call to the function
echo -e "\n$_funcname_ \"\${params[@]}\"\n" >> "$tmpfile"
#
# DONE: EXECUTE THE TEMPORARY FILE WITH SUDO
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sudo bash "$tmpfile"
rm "$tmpfile"
}
resolve_path() {
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
}
check_or_make_symlink() {
source /home/menno/dotfiles/bin/helpers/functions.sh
SOURCE="$1"
TARGET="$2"
# Take any ~ and replace it with $HOME
SOURCE="${SOURCE/#\~/$HOME}"
TARGET="${TARGET/#\~/$HOME}"
# Ensure the parent directory of the target exists
mkdir -p "$(dirname "$TARGET")"
# if source doesn't exist it's likely a secret that hasn't been decrypted yet
if [ ! -e "$SOURCE" ]; then
printfe "%s\n" "yellow" " - Source $SOURCE doesn't exist"
return
fi
SOURCE=$(resolve_path "$SOURCE")
TARGET=$(resolve_path "$TARGET")
# Check if we have permissions to create the symlink
if [ ! -w "$(dirname "$TARGET")" ]; then
# Check if link exists
if [ -L "$TARGET" ]; then
# Check if it points to the correct location
if [ "$(readlink "$TARGET")" != "$SOURCE" ]; then
exesudo check_or_make_symlink "$SOURCE" "$TARGET"
return
fi
else
# Link doesn't exist but we don't have permissions to create it, so we should try to create it with sudosudo
exesudo check_or_make_symlink "$SOURCE" "$TARGET"
fi
return
fi
# If target is already a symlink, we should check if it points to the correct location
if [ -L "$TARGET" ]; then
if [ "$(readlink "$TARGET")" != "$SOURCE" ]; then
printfe "%s\n" "yellow" " - Symlink $TARGET exists but points to the wrong location"
printfe "%s\n" "yellow" " Expected: $SOURCE"
printfe "%s\n" "yellow" " Actual: $(readlink "$TARGET")"
printfe "%s\n" "yellow" " Fixing symlink"
rm "$TARGET"
mkdir -p "$(dirname "$TARGET")"
ln -s "$SOURCE" "$TARGET"
printfe "%s\n" "green" " Created symlink $TARGET -> $SOURCE"
return
fi
fi
# If target is a file and it's not a symlink, we should back it up
if [ -f "$TARGET" ] && [ ! -L "$TARGET" ]; then
printfe "%s\n" "yellow" " - File $TARGET exists, backing up and creating symlink"
mv "$TARGET" "$TARGET.bak"
fi
# If the target is already a symlink, and it points to the correct location, we should return and be happy
if [ -L "$TARGET" ]; then
printfe "%s" "green" " - OK: "
printfe "%-30s" "blue" "$SOURCE"
printfe "%s" "cyan" " -> "
printfe "%-30s\n" "blue" "$TARGET"
return
fi
# Create the symlink
mkdir -p "$(dirname "$TARGET")"
ln -s "$SOURCE" "$TARGET"
# Check if the symlink was created successfully
if [ ! -L "$TARGET" ]; then
printfe "%s\n" "red" " - Failed to create symlink $TARGET -> $SOURCE"
return
fi
printfe "%s" "green" " - Added new symlink: "
printfe "%-30s" "blue" "$SOURCE"
printfe "%s" "cyan" " -> "
printfe "%-30s\n" "blue" "$TARGET"
}
clear_line() {
echo -en "\r"
}