From 6aa087cf0a44cbf26ff9ba0550b3ed5318c044d8 Mon Sep 17 00:00:00 2001 From: Peter Wood Date: Sun, 30 Nov 2025 19:39:45 -0500 Subject: [PATCH] feat: Add uninstall script for Fabric AI CLI with logging and OS detection --- .github/prompts/removefabric.prompt.md | 11 ++ .gitignore | 2 + uninstall-fabric.sh | 214 +++++++++++++++++++++++++ 3 files changed, 227 insertions(+) create mode 100644 .github/prompts/removefabric.prompt.md create mode 100755 uninstall-fabric.sh diff --git a/.github/prompts/removefabric.prompt.md b/.github/prompts/removefabric.prompt.md new file mode 100644 index 0000000..89500bf --- /dev/null +++ b/.github/prompts/removefabric.prompt.md @@ -0,0 +1,11 @@ +Create a portable bash shell script to safely uninstall the Fabric AI CLI and related packages on Debian, Ubuntu, and Fedora systems. The script must: + +- Detect the operating system and select the appropriate package manager (`apt`, `dnf`, or `yum`). +- Uninstall Fabric packages installed via system package managers and Python package managers (`pip`, `pip3`). +- Check for errors after each removal step; abort the script if a critical error occurs. +- Prompt the user for confirmation before making any changes. +- Advise the user to reboot the system if required after uninstallation. +- Log all actions and errors to a user-specified log file. +- Be fully self-contained and compatible with bash. + +Reference the official [Fabric documentation](https://github.com/danielmiessler/Fabric) and your distribution’s package manager documentation for implementation details. \ No newline at end of file diff --git a/.gitignore b/.gitignore index ab46f26..07a54c8 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ _book # Runtime generated files logs/ +uninstall-fabric.log immich_backups/*.gz # Backup files - ignore most backups but keep current state files crontab/crontab-backups/*/archive/ @@ -36,6 +37,7 @@ crontab/crontab-backups/*/archive/ # can be downloaded from immich/b2-linux + # Generated dotfiles - these are created dynamically by bootstrap process dotfiles/my-aliases.zsh diff --git a/uninstall-fabric.sh b/uninstall-fabric.sh new file mode 100755 index 0000000..8c87ee0 --- /dev/null +++ b/uninstall-fabric.sh @@ -0,0 +1,214 @@ +#!/bin/bash + +# uninstall-fabric.sh +# +# Description: Safely uninstalls the Fabric AI CLI (Daniel Miessler) and related configuration. +# Avoids removing the 'fabric' Python deployment library. +# Detects OS and uses appropriate package managers if applicable. +# Logs all actions to a file. +# +# Usage: ./uninstall-fabric.sh +# +# Author: GitHub Copilot + +set -u + +# Configuration +LOG_FILE="uninstall-fabric.log" +CURRENT_DATE=$(date +'%Y-%m-%d %H:%M:%S') + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Initialize log file +echo "Fabric AI CLI Uninstallation Log - Started at $CURRENT_DATE" > "$LOG_FILE" + +# Logging functions +log() { + local message="$1" + echo -e "[$(date +'%H:%M:%S')] $message" | tee -a "$LOG_FILE" +} + +info() { + local message="$1" + echo -e "${BLUE}[INFO]${NC} $message" | tee -a "$LOG_FILE" +} + +success() { + local message="$1" + echo -e "${GREEN}[SUCCESS]${NC} $message" | tee -a "$LOG_FILE" +} + +warning() { + local message="$1" + echo -e "${YELLOW}[WARNING]${NC} $message" | tee -a "$LOG_FILE" +} + +error() { + local message="$1" + echo -e "${RED}[ERROR]${NC} $message" | tee -a "$LOG_FILE" + exit 1 +} + +# Function to detect Operating System +detect_os() { + if [[ -f /etc/os-release ]]; then + # shellcheck source=/dev/null + . /etc/os-release + OS_NAME=$ID + VERSION_ID=$VERSION_ID + info "Detected OS: $NAME ($ID) $VERSION_ID" + else + error "Could not detect operating system. /etc/os-release file not found." + fi +} + +# Function to check for root privileges +check_privileges() { + if [[ $EUID -ne 0 ]]; then + warning "This script is not running as root." + warning "System package removal might fail or require sudo password." + else + info "Running with root privileges." + fi +} + +# Function to confirm action +confirm_execution() { + echo -e "\n${YELLOW}WARNING: This script will attempt to uninstall the Fabric AI CLI (Daniel Miessler).${NC}" + echo -e "It will NOT remove the 'fabric' Python deployment library." + echo -e "It will remove the 'fabric' binary if identified as the AI tool, and configuration files." + echo -e "Please ensure you have backups if necessary.\n" + + read -p "Do you want to proceed? (y/N): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + info "Operation cancelled by user." + exit 0 + fi +} + +# Function to check if a binary is the Fabric AI tool +is_fabric_ai_tool() { + local bin_path="$1" + # Check help output for keywords + # The AI tool usually mentions 'patterns', 'context', 'session', 'model' + if "$bin_path" --help 2>&1 | grep -qE "Daniel Miessler|patterns|context|session|model"; then + return 0 + fi + return 1 +} + +# Function to uninstall binary +uninstall_binary() { + local bin_path + bin_path=$(command -v fabric) + + if [[ -n "$bin_path" ]]; then + info "Found 'fabric' binary at: $bin_path" + + if is_fabric_ai_tool "$bin_path"; then + info "Identified as Fabric AI CLI." + + # Check if owned by system package + local pkg_owner="" + if [[ "$OS_NAME" =~ (debian|ubuntu|linuxmint|pop|kali) ]]; then + if dpkg -S "$bin_path" &> /dev/null; then + pkg_owner=$(dpkg -S "$bin_path" | cut -d: -f1) + fi + elif [[ "$OS_NAME" =~ (fedora|centos|rhel|almalinux|rocky) ]]; then + if rpm -qf "$bin_path" &> /dev/null; then + pkg_owner=$(rpm -qf "$bin_path") + fi + fi + + if [[ -n "$pkg_owner" ]]; then + info "Binary is owned by system package: $pkg_owner" + info "Removing package $pkg_owner..." + local sudo_prefix="" + [[ $EUID -ne 0 ]] && sudo_prefix="sudo" + + if [[ "$OS_NAME" =~ (debian|ubuntu|linuxmint|pop|kali) ]]; then + $sudo_prefix apt-get remove -y "$pkg_owner" >> "$LOG_FILE" 2>&1 || error "Failed to remove package $pkg_owner" + else + $sudo_prefix dnf remove -y "$pkg_owner" >> "$LOG_FILE" 2>&1 || error "Failed to remove package $pkg_owner" + fi + success "Removed system package $pkg_owner." + else + info "Binary is not owned by a system package. Removing manually..." + rm -f "$bin_path" || error "Failed to remove $bin_path" + success "Removed binary $bin_path." + fi + else + warning "The binary at $bin_path does not appear to be the Fabric AI CLI. Skipping removal to be safe." + warning "Run '$bin_path --help' to verify what it is." + fi + else + info "'fabric' binary not found in PATH." + fi +} + +# Function to uninstall from pipx +uninstall_pipx() { + if command -v pipx &> /dev/null; then + info "Checking pipx for 'fabric'..." + if pipx list | grep -q "package fabric"; then + info "Found 'fabric' installed via pipx. Uninstalling..." + pipx uninstall fabric >> "$LOG_FILE" 2>&1 || error "Failed to uninstall fabric via pipx" + success "Uninstalled fabric via pipx." + else + info "'fabric' not found in pipx." + fi + fi +} + +# Function to remove configuration files +remove_config() { + local config_dirs=( + "$HOME/.config/fabric" + "$HOME/.fabric" + "$HOME/.local/share/fabric" + ) + + for dir in "${config_dirs[@]}"; do + if [[ -d "$dir" ]]; then + info "Found configuration directory: $dir" + rm -rf "$dir" || error "Failed to remove $dir" + success "Removed $dir." + fi + done +} + +# Main execution flow +main() { + detect_os + check_privileges + confirm_execution + + info "Starting uninstallation process..." + + # Check pipx first as it manages its own binaries + uninstall_pipx + + # Check binary + uninstall_binary + + # Remove config + remove_config + + echo -e "\n----------------------------------------------------------------" + success "Uninstallation steps completed." + info "A log of this operation has been saved to: $LOG_FILE" + echo -e "${YELLOW}Note: If you removed system-level components, a reboot might be recommended.${NC}" + echo -e "----------------------------------------------------------------" +} + +# Trap interrupts +trap 'echo -e "\n${RED}Script interrupted by user.${NC}"; exit 1' INT TERM + +# Run main +main