diff --git a/bin/clean.sh b/bin/clean.sh index eba175f..9a0c1ce 100755 --- a/bin/clean.sh +++ b/bin/clean.sh @@ -768,6 +768,66 @@ perform_cleanup() { log_success "Systemd core dumps" fi + # 8. Orphaned packages cleanup (Enhanced Debloat) + if command -v apt-get &>/dev/null; then + if [[ "$DRY_RUN" != "true" ]]; then + # Remove orphaned packages + local orphans_output=$(sudo apt-get autoremove -y 2>&1) + if echo "$orphans_output" | grep -q "packages will be removed"; then + log_success "Orphaned packages removed" + fi + else + # Check for orphaned packages + local orphaned=$(apt-mark showauto 2>/dev/null | \ + xargs apt-cache rdepends --installed 2>/dev/null | \ + grep -v "^ " | grep -v "^Reverse" | wc -l) + if [[ $orphaned -gt 0 ]]; then + log_success "Would remove orphaned packages [DRY RUN]" + fi + fi + fi + + # 9. Deborphan cleanup (if installed) + if command -v deborphan &>/dev/null; then + if [[ "$DRY_RUN" != "true" ]]; then + local orphan_list=$(deborphan) + if [[ -n "$orphan_list" ]]; then + echo "$orphan_list" | sudo xargs apt-get -y purge &>/dev/null || true + log_success "Deborphan packages removed" + fi + else + local orphan_count=$(deborphan | wc -l) + if [[ $orphan_count -gt 0 ]]; then + log_success "Would remove $orphan_count deborphan package(s) [DRY RUN]" + fi + fi + fi + + # 10. Optional bloatware removal (gnome-games, gnome-software) + # Note: Only removes if explicitly confirmed + if [[ "${FUB_REMOVE_BLOAT:-}" == "true" ]]; then + local bloat_packages=("gnome-games" "gnome-software" "gnome-mahjongg" "gnome-mines" "gnome-sudoku" "aisleriot") + if [[ "$DRY_RUN" != "true" ]]; then + for pkg in "${bloat_packages[@]}"; do + if dpkg -l | grep -q "^ii.*$pkg"; then + sudo apt-get purge -y "$pkg" &>/dev/null || true + fi + done + log_success "Bloatware packages removed" + else + local bloat_count=0 + for pkg in "${bloat_packages[@]}"; do + if dpkg -l | grep -q "^ii.*$pkg"; then + ((bloat_count++)) + fi + done + if [[ $bloat_count -gt 0 ]]; then + log_success "Would remove $bloat_count bloatware package(s) [DRY RUN]" + echo -e " ${GRAY}Set FUB_REMOVE_BLOAT=true to enable bloatware removal${NC}" + fi + fi + fi + end_section fi diff --git a/bin/optimize.sh b/bin/optimize.sh index d9fd1e3..2ca52e9 100755 --- a/bin/optimize.sh +++ b/bin/optimize.sh @@ -574,6 +574,73 @@ main() { done fi + # ===== Additional Ubuntu Optimizations ===== + + # Performance tuning (disable tracker, hibernation) + echo "" + echo -e "${BLUE}${ICON_ARROW}${NC} Performance tuning..." + + # Disable GNOME Tracker (file indexing) + if systemctl --user is-active --quiet tracker-miner-fs.service 2>/dev/null; then + echo -ne " ${GRAY}→${NC} Disable GNOME Tracker (file indexing)..." + systemctl --user mask tracker-store.service tracker-miner-fs.service tracker-miner-rss.service tracker-extract.service tracker-miner-apps.service tracker-writeback.service &>/dev/null || true + systemctl --user stop tracker-store.service tracker-miner-fs.service tracker-miner-rss.service tracker-extract.service tracker-miner-apps.service tracker-writeback.service &>/dev/null || true + echo -e " ${GREEN}✓${NC}" + fi + + # Disable hibernation (faster boot) + if [[ -f /etc/systemd/logind.conf ]]; then + if ! grep -q "HandleLidSwitch=suspend" /etc/systemd/logind.conf 2>/dev/null; then + echo -ne " ${GRAY}→${NC} Disable hibernation for faster boot..." + sudo mkdir -p /etc/systemd/logind.conf.d 2>/dev/null || true + echo -e "[Login]\nHandleLidSwitch=suspend\nHandleLidSwitchDocked=ignore" | sudo tee /etc/systemd/logind.conf.d/fub-performance.conf &>/dev/null || true + echo -e " ${GREEN}✓${NC}" + fi + fi + + # Reduce swappiness for better performance (if not already set) + local current_swappiness=$(cat /proc/sys/vm/swappiness 2>/dev/null || echo "60") + if [[ $current_swappiness -gt 10 ]]; then + echo -ne " ${GRAY}→${NC} Reduce swappiness to 10 (better performance)..." + echo "vm.swappiness=10" | sudo tee /etc/sysctl.d/99-fub-swappiness.conf &>/dev/null || true + sudo sysctl vm.swappiness=10 &>/dev/null || true + echo -e " ${GREEN}✓${NC}" + fi + + # Nerd Fonts installer (optional) + if [[ "${FUB_INSTALL_NERDFONTS:-}" == "true" ]]; then + echo "" + echo -e "${BLUE}${ICON_ARROW}${NC} Installing Nerd Fonts..." + + local fonts_dir="$HOME/.local/share/fonts" + mkdir -p "$fonts_dir" + + # Download and install popular Nerd Fonts + local nerd_fonts=("JetBrainsMono" "FiraCode" "Hack" "Meslo") + + for font in "${nerd_fonts[@]}"; do + if [[ ! -d "$fonts_dir/$font" ]]; then + echo -ne " ${GRAY}→${NC} Downloading $font Nerd Font..." + local font_url="https://github.com/ryanoasis/nerd-fonts/releases/latest/download/${font}.zip" + local temp_zip="/tmp/${font}.zip" + + if curl -fsSL "$font_url" -o "$temp_zip" 2>/dev/null; then + mkdir -p "$fonts_dir/$font" + unzip -q "$temp_zip" -d "$fonts_dir/$font" 2>/dev/null || true + rm -f "$temp_zip" + echo -e " ${GREEN}✓${NC}" + else + echo -e " ${YELLOW}skipped${NC}" + fi + fi + done + + # Update font cache + echo -ne " ${GRAY}→${NC} Updating font cache..." + fc-cache -fv &>/dev/null || true + echo -e " ${GREEN}✓${NC}" + fi + # Show login item reminder at the end of optimization log local -a login_items_list=() while IFS= read -r login_item; do diff --git a/bin/swap.sh b/bin/swap.sh new file mode 100755 index 0000000..a3632fe --- /dev/null +++ b/bin/swap.sh @@ -0,0 +1,289 @@ +#!/bin/bash +# Fub - Swap File Manager +# Interactive swap file creation and management for Ubuntu +# +# Usage: +# swap.sh # Launch interactive swap manager +# swap.sh --help # Show help information + +set -euo pipefail + +# Get script directory and source common functions +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/../lib/common.sh" + +# Check and install fzf if needed (reuse from uninstall.sh) +ensure_fzf() { + if command -v fzf &>/dev/null; then + return 0 + fi + + echo -e "${YELLOW}fzf not found.${NC} Installing fzf for better interaction..." + + # Try to install via apt first + if command -v apt-get &>/dev/null; then + if sudo apt-get install -y fzf &>/dev/null; then + echo -e "${GREEN}✓${NC} fzf installed via apt" + return 0 + fi + fi + + echo -e "${RED}Please install fzf to use interactive swap manager${NC}" + return 1 +} + +# Get current swap status +get_swap_status() { + if swapon --show 2>/dev/null | grep -q "/swapfile"; then + local current_size=$(swapon --show --bytes --noheadings 2>/dev/null | grep "/swapfile" | awk '{print $3}') + if [[ -n "$current_size" ]]; then + local size_gb=$((current_size / 1024 / 1024 / 1024)) + echo "${size_gb}GB" + else + echo "Unknown" + fi + else + echo "None" + fi +} + +# Show current memory and swap info +show_memory_info() { + echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo -e "${BLUE}Current Memory Status${NC}" + echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + + # Memory info + local total_mem=$(free -h | awk '/^Mem:/{print $2}') + local used_mem=$(free -h | awk '/^Mem:/{print $3}') + local free_mem=$(free -h | awk '/^Mem:/{print $4}') + + echo -e " ${GRAY}RAM:${NC} Total: ${GREEN}$total_mem${NC} | Used: ${YELLOW}$used_mem${NC} | Free: ${CYAN}$free_mem${NC}" + + # Swap info + local swap_status=$(get_swap_status) + if [[ "$swap_status" == "None" ]]; then + echo -e " ${GRAY}Swap:${NC} ${YELLOW}No swap file configured${NC}" + else + local total_swap=$(free -h | awk '/^Swap:/{print $2}') + local used_swap=$(free -h | awk '/^Swap:/{print $3}') + echo -e " ${GRAY}Swap:${NC} Total: ${GREEN}$total_swap${NC} | Used: ${YELLOW}$used_swap${NC} | Current: ${CYAN}$swap_status${NC}" + fi + + echo "" +} + +# Create swap file with specified size +create_swap_file() { + local size_gb="$1" + local swap_path="/swapfile" + + echo -e "${BLUE}Creating ${size_gb}GB swap file...${NC}" + echo "" + + # Disable existing swap if any + if swapon --show 2>/dev/null | grep -q "$swap_path"; then + echo -e " ${BLUE}→${NC} Disabling existing swap..." + sudo swapoff "$swap_path" 2>/dev/null || true + fi + + # Remove old swap file if exists + if [[ -f "$swap_path" ]]; then + echo -e " ${BLUE}→${NC} Removing old swap file..." + sudo rm -f "$swap_path" + fi + + # Create new swap file + echo -e " ${BLUE}→${NC} Creating ${size_gb}GB swap file (this may take a moment)..." + if sudo fallocate -l "${size_gb}G" "$swap_path" 2>/dev/null || \ + sudo dd if=/dev/zero of="$swap_path" bs=1G count="$size_gb" status=progress 2>/dev/null; then + + # Set permissions + echo -e " ${BLUE}→${NC} Setting permissions..." + sudo chmod 600 "$swap_path" + + # Format as swap + echo -e " ${BLUE}→${NC} Formatting as swap..." + sudo mkswap "$swap_path" &>/dev/null + + # Enable swap + echo -e " ${BLUE}→${NC} Enabling swap..." + sudo swapon "$swap_path" + + # Add to /etc/fstab if not present + if ! grep -q "$swap_path" /etc/fstab 2>/dev/null; then + echo -e " ${BLUE}→${NC} Adding to /etc/fstab for persistence..." + echo "$swap_path none swap sw 0 0" | sudo tee -a /etc/fstab > /dev/null + fi + + echo "" + echo -e "${GREEN}✓ Swap file created successfully!${NC}" + echo "" + show_memory_info + + return 0 + else + echo -e "${RED}✗ Failed to create swap file${NC}" + return 1 + fi +} + +# Remove swap file +remove_swap_file() { + local swap_path="/swapfile" + + echo -e "${BLUE}Removing swap file...${NC}" + echo "" + + # Disable swap + if swapon --show 2>/dev/null | grep -q "$swap_path"; then + echo -e " ${BLUE}→${NC} Disabling swap..." + sudo swapoff "$swap_path" || true + fi + + # Remove from /etc/fstab + if grep -q "$swap_path" /etc/fstab 2>/dev/null; then + echo -e " ${BLUE}→${NC} Removing from /etc/fstab..." + sudo sed -i "\|$swap_path|d" /etc/fstab + fi + + # Delete file + if [[ -f "$swap_path" ]]; then + echo -e " ${BLUE}→${NC} Deleting swap file..." + sudo rm -f "$swap_path" + fi + + echo "" + echo -e "${GREEN}✓ Swap file removed${NC}" + echo "" + show_memory_info +} + +# Interactive swap size selection +select_swap_size() { + # Prepare size options + local sizes=("2GB" "4GB" "8GB" "16GB" "32GB" "Custom" "Remove Swap" "Cancel") + + local selection=$(printf '%s\n' "${sizes[@]}" | fzf \ + --height=15 \ + --reverse \ + --border=rounded \ + --header="Select swap file size:" \ + --prompt="Size > " \ + --pointer="▶" \ + --color='fg:#d0d0d0,bg:#1c1c1c,hl:#5fd7ff' \ + --color='fg+:#ffffff,bg+:#262626,hl+:#5fd7ff' \ + --color='info:#afaf87,prompt:#719e07,pointer:#af5fff' \ + --color='marker:#87ff00,spinner:#af5fff,header:#87afaf') + + echo "$selection" +} + +# Main function +main() { + # Check for help + if [[ "${1:-}" == "--help" ]] || [[ "${1:-}" == "-h" ]]; then + cat < "8") + local size_num=$(echo "$selected_size" | grep -o '[0-9]*') + echo "" + read -p "Create ${size_num}GB swap file? (y/N): " confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + create_swap_file "$size_num" + else + echo -e "${GRAY}Cancelled.${NC}" + fi + ;; + esac +} + +main "$@" diff --git a/fub b/fub index a49d4a7..8b586b8 100755 --- a/fub +++ b/fub @@ -139,6 +139,7 @@ show_help() { printf " %s%-28s%s %s\n" "$GREEN" "fub uninstall" "$NC" "Remove applications completely" printf " %s%-28s%s %s\n" "$GREEN" "fub optimize" "$NC" "System health check & optimization" printf " %s%-28s%s %s\n" "$GREEN" "fub analyze" "$NC" "Interactive disk space explorer" + printf " %s%-28s%s %s\n" "$GREEN" "fub swap" "$NC" "Manage swap file (create/remove)" printf " %s%-28s%s %s\n" "$GREEN" "fub touchid" "$NC" "Configure Touch ID for sudo" printf " %s%-28s%s %s\n" "$GREEN" "fub update" "$NC" "Update Fub to the latest version" printf " %s%-28s%s %s\n" "$GREEN" "fub remove" "$NC" "Remove Fub from the system" @@ -473,6 +474,7 @@ show_main_menu() { printf '\r\033[2K%s\n' "$(show_menu_option 2 "Uninstall Apps - Remove applications completely" "$([[ $selected -eq 2 ]] && echo true || echo false)")" printf '\r\033[2K%s\n' "$(show_menu_option 3 "Optimize System - System health & tuning" "$([[ $selected -eq 3 ]] && echo true || echo false)")" printf '\r\033[2K%s\n' "$(show_menu_option 4 "Analyze Disk - Interactive space explorer" "$([[ $selected -eq 4 ]] && echo true || echo false)")" + printf '\r\033[2K%s\n' "$(show_menu_option 5 "Swap Manager - Create/manage swap file" "$([[ $selected -eq 5 ]] && echo true || echo false)")" if [[ -t 0 ]]; then printf '\r\033[2K\n' @@ -539,7 +541,7 @@ interactive_main_menu() { case "$key" in "UP") ((current_option > 1)) && ((current_option--)) ;; - "DOWN") ((current_option < 4)) && ((current_option++)) ;; + "DOWN") ((current_option < 5)) && ((current_option++)) ;; "ENTER") show_cursor case $current_option in @@ -547,6 +549,7 @@ interactive_main_menu() { 2) exec "$SCRIPT_DIR/bin/uninstall.sh" ;; 3) exec "$SCRIPT_DIR/bin/optimize.sh" ;; 4) exec "$SCRIPT_DIR/bin/analyze.sh" ;; + 5) exec "$SCRIPT_DIR/bin/swap.sh" ;; esac ;; "CHAR:1") @@ -565,6 +568,10 @@ interactive_main_menu() { show_cursor exec "$SCRIPT_DIR/bin/analyze.sh" ;; + "CHAR:5") + show_cursor + exec "$SCRIPT_DIR/bin/swap.sh" + ;; "HELP") show_cursor clear @@ -590,6 +597,9 @@ main() { "analyze") exec "$SCRIPT_DIR/bin/analyze.sh" "${@:2}" ;; + "swap") + exec "$SCRIPT_DIR/bin/swap.sh" "${@:2}" + ;; "touchid") exec "$SCRIPT_DIR/bin/touchid.sh" "${@:2}" ;;