From 8971d087a3849f75a85d01f0e7d9f8d169939f86 Mon Sep 17 00:00:00 2001 From: Menno van Leeuwen Date: Tue, 23 Sep 2025 13:59:48 +0000 Subject: [PATCH] Remove secrets and auto-start actions and update imports --- bin/actions/__init__.py | 0 bin/actions/auto-start.py | 87 ------------------ bin/actions/hello.py | 27 +++--- bin/actions/help.py | 4 +- bin/actions/lint.py | 24 ++--- bin/actions/secrets.py | 185 -------------------------------------- bin/actions/service.py | 14 +-- bin/actions/source.py | 11 ++- bin/actions/timers.py | 8 +- bin/actions/update.py | 4 +- bin/dotf | 10 --- bin/helpers/__init__.py | 0 bin/helpers/functions.py | 4 +- bin/resources/help.txt | 6 -- 14 files changed, 58 insertions(+), 326 deletions(-) create mode 100644 bin/actions/__init__.py delete mode 100755 bin/actions/auto-start.py delete mode 100755 bin/actions/secrets.py create mode 100644 bin/helpers/__init__.py diff --git a/bin/actions/__init__.py b/bin/actions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bin/actions/auto-start.py b/bin/actions/auto-start.py deleted file mode 100755 index e767855..0000000 --- a/bin/actions/auto-start.py +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -import time -import subprocess - -# Import helper functions -sys.path.append(os.path.join(os.path.expanduser("~/.dotfiles"), "bin")) -from helpers.functions import printfe, run_command - - -def check_command_exists(command): - """Check if a command is available in the system""" - try: - subprocess.run( - ["which", command], - check=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) - return True - except subprocess.CalledProcessError: - return False - - -def list_screen_sessions(): - """List all screen sessions""" - success, output = run_command(["screen", "-ls"]) - return output - - -def wipe_dead_sessions(): - """Check and clean up dead screen sessions""" - screen_list = list_screen_sessions() - if "Dead" in screen_list: - print("Found dead sessions, cleaning up...") - run_command(["screen", "-wipe"]) - - -def is_app_running(app_name): - """Check if an app is already running in a screen session""" - screen_list = list_screen_sessions() - return app_name in screen_list - - -def start_app(app_name, command): - """Start an application in a screen session""" - printfe("green", f"Starting {app_name} with command: {command}...") - run_command(["screen", "-dmS", app_name] + command.split()) - time.sleep(1) # Give it a moment to start - - -def main(): - # Define dictionary with app_name => command mapping - apps = { - "vesktop": "vesktop", - "ktailctl": "flatpak run org.fkoehler.KTailctl", - "nemo-desktop": "nemo-desktop", - } - - # Clean up dead sessions if any - wipe_dead_sessions() - - print("Starting auto-start applications...") - for app_name, command in apps.items(): - # Get the binary name (first part of the command) - command_binary = command.split()[0] - - # Check if the command exists - if check_command_exists(command_binary): - # Check if the app is already running - if is_app_running(app_name): - printfe("yellow", f"{app_name} is already running. Skipping...") - continue - - # Start the application - start_app(app_name, command) - - # Display screen sessions - print(list_screen_sessions()) - - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/bin/actions/hello.py b/bin/actions/hello.py index f948672..572dc3d 100755 --- a/bin/actions/hello.py +++ b/bin/actions/hello.py @@ -1,13 +1,14 @@ #!/usr/bin/env python3 +"""Display welcome message and system information.""" + 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 +sys.path.append(os.path.join(os.path.dirname(__file__), "..")) +from helpers.functions import logo, _rainbow_color, COLORS def get_last_ssh_login(): @@ -17,12 +18,16 @@ def get_last_ssh_login(): ["lastlog", "-u", os.environ.get("USER", "")], capture_output=True, text=True, + check=False, ) # If lastlog didn't work try lastlog2 if result.returncode != 0: result = subprocess.run( - ["lastlog2", os.environ.get("USER", "")], capture_output=True, text=True + ["lastlog2", os.environ.get("USER", "")], + capture_output=True, + text=True, + check=False, ) if result.returncode == 0: @@ -38,9 +43,7 @@ def get_last_ssh_login(): 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)}") + except (subprocess.CalledProcessError, FileNotFoundError): return None @@ -67,6 +70,7 @@ def check_dotfiles_status(): cwd=dotfiles_path, capture_output=True, text=True, + check=False, ) if result.stdout.strip(): @@ -85,6 +89,7 @@ def check_dotfiles_status(): cwd=dotfiles_path, capture_output=True, text=True, + check=False, ) if result.returncode == 0: status["commit_hash"] = result.stdout.strip() @@ -97,13 +102,14 @@ def check_dotfiles_status(): stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True, + check=False, ) if result.returncode == 0: status["unpushed"] = len(result.stdout.splitlines()) return status - except Exception as e: - print(f"Error checking dotfiles status: {str(e)}") + except (OSError, subprocess.SubprocessError) as e: + print(f"Error checking dotfiles status: {e}") return None @@ -119,7 +125,7 @@ def get_condensed_status(): count = len(items) if count > 0: status_parts.append(f"[!] {count} file(s) in trash") - except Exception: + except OSError: pass # Check dotfiles status @@ -182,6 +188,7 @@ def welcome(): def main(): + """Main entry point for the hello action.""" logo(continue_after=True) welcome() return 0 diff --git a/bin/actions/help.py b/bin/actions/help.py index 43151a4..91c4a9c 100755 --- a/bin/actions/help.py +++ b/bin/actions/help.py @@ -1,10 +1,12 @@ #!/usr/bin/env python3 +"""Display help information for the dotfiles system.""" + import os import sys # Import helper functions -sys.path.append(os.path.join(os.path.expanduser("~/.dotfiles"), "bin")) +sys.path.append(os.path.join(os.path.dirname(__file__), "..")) from helpers.functions import printfe, println, logo diff --git a/bin/actions/lint.py b/bin/actions/lint.py index d1a2142..aed99ec 100755 --- a/bin/actions/lint.py +++ b/bin/actions/lint.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +"""Run linters on dotfiles.""" + import os import sys import subprocess @@ -7,7 +9,7 @@ import argparse from pathlib import Path # Import helper functions -sys.path.append(os.path.join(os.path.dirname(os.path.dirname(__file__)))) +sys.path.append(os.path.join(os.path.dirname(__file__), "..")) from helpers.functions import printfe, command_exists DOTFILES_ROOT = os.path.expanduser("~/.dotfiles") @@ -85,16 +87,6 @@ def lint_python(fix=False): exit_code = 0 - # Check for pylint - if command_exists("pylint"): - printfe("blue", "Running pylint...") - files_to_lint = [str(f) for f in python_files] - result = subprocess.run(["pylint"] + files_to_lint, check=False) - if result.returncode != 0: - exit_code = 1 - else: - printfe("yellow", "pylint is not installed. Skipping Python linting.") - # Check for black if command_exists("black"): printfe( @@ -111,6 +103,16 @@ def lint_python(fix=False): else: printfe("yellow", "black is not installed. Skipping Python formatting.") + # Check for pylint + if command_exists("pylint"): + printfe("blue", "Running pylint...") + files_to_lint = [str(f) for f in python_files] + result = subprocess.run(["pylint"] + files_to_lint, check=False) + if result.returncode != 0: + exit_code = 1 + else: + printfe("yellow", "pylint is not installed. Skipping Python linting.") + if not command_exists("pylint") and not command_exists("black"): printfe( "red", diff --git a/bin/actions/secrets.py b/bin/actions/secrets.py deleted file mode 100755 index 880c3ee..0000000 --- a/bin/actions/secrets.py +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -import subprocess -import hashlib -import glob - -# Import helper functions -sys.path.append(os.path.join(os.path.expanduser("~/.dotfiles"), "bin")) -from helpers.functions import printfe, run_command - - -def get_password(): - """Get password from 1Password""" - op_cmd = "op" - - # Try to get the password - success, output = run_command( - [op_cmd, "read", "op://Dotfiles/Dotfiles Secrets/password"] - ) - - if not success: - printfe("red", "Failed to fetch password from 1Password.") - return None - - # Check if we need to use a token - if "use 'op item get" in output: - # Extract the token - token = output.split("use 'op item get ")[1].split(" --")[0] - printfe("cyan", f"Got fetch token: {token}") - - # Use the token to get the actual password - success, password = run_command( - [op_cmd, "item", "get", token, "--reveal", "--fields", "password"] - ) - if not success: - return None - return password - else: - # We already got the password - return output - - -def prompt_for_password(): - """Ask for password manually""" - import getpass - - printfe("cyan", "Enter the password manually: ") - password = getpass.getpass("") - - if not password: - printfe("red", "Password cannot be empty.") - sys.exit(1) - - printfe("green", "Password entered successfully.") - return password - - -def calculate_checksum(file_path): - """Calculate SHA256 checksum of a file""" - sha256_hash = hashlib.sha256() - with open(file_path, "rb") as f: - for byte_block in iter(lambda: f.read(4096), b""): - sha256_hash.update(byte_block) - return sha256_hash.hexdigest() - - -def encrypt_folder(folder_path, password): - """Recursively encrypt files in a folder""" - for item in glob.glob(os.path.join(folder_path, "*")): - # Skip .gpg and .sha256 files - if item.endswith(".gpg") or item.endswith(".sha256"): - continue - - # Handle directories recursively - if os.path.isdir(item): - encrypt_folder(item, password) - continue - - # Calculate current checksum - current_checksum = calculate_checksum(item) - checksum_file = f"{item}.sha256" - - # Check if file changed since last encryption - if os.path.exists(checksum_file): - with open(checksum_file, "r") as f: - previous_checksum = f.read().strip() - - if current_checksum == previous_checksum: - continue - - # Remove existing .gpg file if it exists - gpg_file = f"{item}.gpg" - if os.path.exists(gpg_file): - os.remove(gpg_file) - - # Encrypt the file - printfe("cyan", f"Encrypting {item}...") - cmd = [ - "gpg", - "--quiet", - "--batch", - "--yes", - "--symmetric", - "--cipher-algo", - "AES256", - "--armor", - "--passphrase", - password, - "--output", - gpg_file, - item, - ] - - success, _ = run_command(cmd) - if success: - printfe("cyan", f"Staging {item} for commit...") - run_command(["git", "add", "-f", gpg_file]) - - # Update checksum file - with open(checksum_file, "w") as f: - f.write(current_checksum) - else: - printfe("red", f"Failed to encrypt {item}") - - -def decrypt_folder(folder_path, password): - """Recursively decrypt files in a folder""" - for item in glob.glob(os.path.join(folder_path, "*")): - # Handle .gpg files - if item.endswith(".gpg"): - output_file = item[:-4] # Remove .gpg extension - printfe("cyan", f"Decrypting {item}...") - - cmd = [ - "gpg", - "--quiet", - "--batch", - "--yes", - "--decrypt", - "--passphrase", - password, - "--output", - output_file, - item, - ] - - success, _ = run_command(cmd) - if not success: - printfe("red", f"Failed to decrypt {item}") - - # Process directories recursively - elif os.path.isdir(item): - printfe("cyan", f"Decrypting folder {item}...") - decrypt_folder(item, password) - - -def main(): - if len(sys.argv) != 2 or sys.argv[1] not in ["encrypt", "decrypt"]: - printfe("red", "Usage: secrets.py [encrypt|decrypt]") - return 1 - - # Get the dotfiles path - dotfiles_path = os.environ.get("DOTFILES_PATH", os.path.expanduser("~/.dotfiles")) - secrets_path = os.path.join(dotfiles_path, "secrets") - - # Get the password - password = get_password() - if not password: - password = prompt_for_password() - - # Perform the requested action - if sys.argv[1] == "encrypt": - printfe("cyan", "Encrypting secrets...") - encrypt_folder(secrets_path, password) - else: # decrypt - printfe("cyan", "Decrypting secrets...") - decrypt_folder(secrets_path, password) - - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/bin/actions/service.py b/bin/actions/service.py index cff8488..dd002ec 100755 --- a/bin/actions/service.py +++ b/bin/actions/service.py @@ -1,12 +1,14 @@ #!/usr/bin/env python3 +"""Manage Docker services.""" + import os import sys import subprocess import argparse # Import helper functions -sys.path.append(os.path.join(os.path.expanduser("~/.dotfiles"), "bin")) +sys.path.append(os.path.join(os.path.dirname(__file__), "..")) from helpers.functions import printfe, println, logo # Base directory for Docker services $HOME/services @@ -42,7 +44,7 @@ def run_docker_compose(args, service_name=None, compose_file=None): cmd.extend(args) printfe("blue", f"Running: {' '.join(cmd)}") - result = subprocess.run(cmd) + result = subprocess.run(cmd, check=False) return result.returncode @@ -248,6 +250,7 @@ def check_service_running(service_name): ["docker", "compose", "-f", compose_file, "ps", "--quiet"], capture_output=True, text=True, + check=False, ) # Count non-empty lines to get container count @@ -259,18 +262,18 @@ def get_systemd_timer_status(timer_name): """Check if a systemd timer is active and enabled, and get next run time""" # Check if timer is active (running/waiting) active_result = subprocess.run( - ["sudo", "systemctl", "is-active", timer_name], capture_output=True, text=True + ["sudo", "systemctl", "is-active", timer_name], capture_output=True, text=True, check=False ) # Check if timer is enabled (will start on boot) enabled_result = subprocess.run( - ["sudo", "systemctl", "is-enabled", timer_name], capture_output=True, text=True + ["sudo", "systemctl", "is-enabled", timer_name], capture_output=True, text=True, check=False ) # Check corresponding service status service_name = timer_name.replace(".timer", ".service") service_result = subprocess.run( - ["sudo", "systemctl", "is-active", service_name], capture_output=True, text=True + ["sudo", "systemctl", "is-active", service_name], capture_output=True, text=True, check=False ) # Get next run time @@ -278,6 +281,7 @@ def get_systemd_timer_status(timer_name): ["sudo", "systemctl", "list-timers", timer_name, "--no-legend"], capture_output=True, text=True, + check=False, ) is_active = active_result.returncode == 0 diff --git a/bin/actions/source.py b/bin/actions/source.py index a173837..79a6f27 100755 --- a/bin/actions/source.py +++ b/bin/actions/source.py @@ -1,12 +1,14 @@ #!/usr/bin/env python3 +"""Generate export commands for Borg environment variables.""" + import os import sys import subprocess -# Add the helpers directory to the path -sys.path.append(os.path.join(os.path.dirname(__file__), "..", "helpers")) -from functions import printfe +# Add the bin directory to the path +sys.path.append(os.path.join(os.path.dirname(__file__), "..")) +from helpers.functions import printfe def get_borg_passphrase(): @@ -73,18 +75,15 @@ def main(): print() printfe("yellow", "Or copy and paste these exports:") print() - # Output the export commands for export_cmd in exports: print(export_cmd) - print() printfe("cyan", "📋 Borg commands (use with sudo -E):") printfe("white", " sudo -E borg list # List all backups") printfe("white", " sudo -E borg info # Repository info") printfe("white", " sudo -E borg list ::archive-name # List files in backup") printfe("white", " sudo -E borg mount . ~/borg-mount # Mount as filesystem") - return 0 diff --git a/bin/actions/timers.py b/bin/actions/timers.py index b48543b..63bf1c3 100755 --- a/bin/actions/timers.py +++ b/bin/actions/timers.py @@ -1,12 +1,14 @@ #!/usr/bin/env python3 +"""Display status of systemd timers.""" + import os import subprocess import sys -# Add the helpers directory to the path -sys.path.append(os.path.join(os.path.dirname(__file__), "..", "helpers")) -from functions import printfe +# Add the bin directory to the path +sys.path.append(os.path.join(os.path.dirname(__file__), "..")) +from helpers.functions import printfe def run_command(cmd, capture_output=True): diff --git a/bin/actions/update.py b/bin/actions/update.py index de2e936..4c5ba77 100755 --- a/bin/actions/update.py +++ b/bin/actions/update.py @@ -1,12 +1,14 @@ #!/usr/bin/env python3 +"""Update the dotfiles system.""" + import os import sys import subprocess import argparse # Import helper functions -sys.path.append(os.path.join(os.path.expanduser("~/.dotfiles"), "bin")) +sys.path.append(os.path.join(os.path.dirname(__file__), "..")) from helpers.functions import printfe, run_command diff --git a/bin/dotf b/bin/dotf index fa3d63a..2cfae88 100755 --- a/bin/dotf +++ b/bin/dotf @@ -43,14 +43,6 @@ def help(args): """Run the help action""" return run_script(f"{DOTFILES_BIN}/actions/help.py", args) -def secrets(args): - """Run the secrets action""" - return run_script(f"{DOTFILES_BIN}/actions/secrets.py", args) - -def auto_start(args): - """Run the auto-start action""" - return run_script(f"{DOTFILES_BIN}/actions/auto-start.py", args) - def service(args): """Run the service/docker action""" return run_script(f"{DOTFILES_BIN}/actions/service.py", args) @@ -119,8 +111,6 @@ def main(): "update": update, "help": help, "hello": hello, - "secrets": secrets, - "auto-start": auto_start, "service": service, "lint": lint, "timers": timers, diff --git a/bin/helpers/__init__.py b/bin/helpers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bin/helpers/functions.py b/bin/helpers/functions.py index 08fb406..1678864 100644 --- a/bin/helpers/functions.py +++ b/bin/helpers/functions.py @@ -7,6 +7,8 @@ import random import shutil import datetime +"""Helper functions for the dotfiles system.""" + try: import pyfiglet except ImportError: @@ -157,7 +159,7 @@ def ensure_dependencies(): if missing_packages: printfe("yellow", f"Missing dependencies: {', '.join(missing_packages)}") install = input("Would you like to install them now? (y/n): ").lower() - if install == "y" or install == "yes": + if install in ("y", "yes"): printfe("cyan", "Installing missing dependencies...") for package in missing_packages: printfe("blue", f"Installing {package}...") diff --git a/bin/resources/help.txt b/bin/resources/help.txt index 2442284..5e33458 100755 --- a/bin/resources/help.txt +++ b/bin/resources/help.txt @@ -6,11 +6,6 @@ Usage: dotf [OPTIONS] [ARGS] --ansible, -A Upgrade Ansible packages --ansible-verbose Upgrade Ansible packages with verbose output (-vvv) --full-speed, -F Use all available cores for compilation (Default: 8 cores) - - secrets: Encrypt and decrypt secrets. - Commands: - encrypt Encrypt all files in the secrets folder - decrypt Decrypt all .gpg files in the secrets folder service: Manage Docker services for development. Commands: @@ -30,6 +25,5 @@ Usage: dotf [OPTIONS] [ARGS] --python Run only Python linters (pylint, black) --fix Auto-fix issues where possible - auto-start: Start a set of pre-defined applications. hello: Shows the welcome message for the terminal. help: Shows this help message