1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-04 21:29:42 +00:00
Files
Mole/mole
2025-10-03 14:21:57 +08:00

353 lines
10 KiB
Bash
Executable File

#!/bin/bash
# Mole - Main Entry Point
# A comprehensive macOS maintenance tool
#
# 🧹 Clean - Remove junk files and optimize system
# 🗑️ Uninstall - Remove applications completely
#
# Usage:
# ./mole # Interactive main menu
# ./mole clean # Direct clean mode
# ./mole uninstall # Direct uninstall mode
# ./mole --help # Show help
set -euo pipefail
# Get script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Source common functions
source "$SCRIPT_DIR/lib/common.sh"
# Version info
VERSION="1.3.0"
MOLE_TAGLINE="can dig deep to clean your Mac."
# Check for updates (non-blocking, cached)
check_for_updates() {
local cache_dir="$HOME/.cache/mole"
local version_cache="$cache_dir/version_check"
local check_interval=86400 # Check once per day (24 hours)
mkdir -p "$cache_dir" 2>/dev/null
# Check if we should run version check (based on cache age)
if [[ -f "$version_cache" ]]; then
local cache_age=$(($(date +%s) - $(stat -f%m "$version_cache" 2>/dev/null || echo 0)))
if [[ $cache_age -lt $check_interval ]]; then
# Cache is still fresh, show cached message if exists
if [[ -s "$version_cache" ]]; then
cat "$version_cache"
fi
return 0
fi
fi
# Run version check in background (non-blocking)
(
local latest_version=""
local timeout=3 # 3 second timeout for version check
# Try to fetch latest version from GitHub with timeout
if command -v curl >/dev/null 2>&1; then
latest_version=$(curl -fsSL --connect-timeout 2 --max-time $timeout \
"https://api.github.com/repos/tw93/mole/releases/latest" 2>/dev/null | \
grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/' | sed 's/^[Vv]//')
elif command -v wget >/dev/null 2>&1; then
latest_version=$(wget -qO- --timeout=$timeout --tries=1 \
"https://api.github.com/repos/tw93/mole/releases/latest" 2>/dev/null | \
grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/' | sed 's/^[Vv]//')
fi
# Compare versions if fetch succeeded
if [[ -n "$latest_version" && "$latest_version" != "$VERSION" ]]; then
# Version mismatch - cache the update message
local msg="${YELLOW}📢 New version available: ${GREEN}${latest_version}${YELLOW} (current: ${VERSION})${NC}\n Run ${GREEN}mole update${YELLOW} to upgrade${NC}"
echo -e "$msg" > "$version_cache"
echo -e "$msg"
else
# Up to date or check failed - clear cache
echo "" > "$version_cache"
fi
# Touch cache file to update timestamp
touch "$version_cache" 2>/dev/null
) &
# Don't wait for background check
disown 2>/dev/null || true
}
show_brand_banner() {
cat << EOF
${GREEN} __ __ _ ${NC}
${GREEN}| \/ | ___ | | ___ ${NC}
${GREEN}| |\/| |/ _ \| |/ _ \\${NC}
${GREEN}| | | | (_) | | __/${NC} ${BLUE}https://github.com/tw93/mole${NC}
${GREEN}|_| |_|\___/|_|\___|${NC} ${GREEN}${MOLE_TAGLINE}${NC}
EOF
}
animate_mole_intro() {
# Skip animation if stdout isn't a TTY (non-interactive)
if [[ ! -t 1 ]]; then
return
fi
clear_screen
printf '\n'
hide_cursor
local -a mole_lines=()
while IFS= read -r line; do
mole_lines+=("$line")
done <<'EOF'
/\_/\
____/ o o \
/~____ =o= /
(______)__m_m)
/ \
__/ /\ \__
/__/ \__\_
EOF
local idx
local body_cutoff=4
local body_color="${PURPLE}"
local ground_color="${GREEN}"
for idx in "${!mole_lines[@]}"; do
if (( idx < body_cutoff )); then
printf "%s\n" "${body_color}${mole_lines[$idx]}${NC}"
else
printf "%s\n" "${ground_color}${mole_lines[$idx]}${NC}"
fi
sleep 0.1
done
printf '\n'
printf "%s\n" "${BLUE}Ready to dig deep...${NC}"
sleep 0.5
printf '\033[2J\033[H'
show_cursor
}
show_version() {
printf 'Mole version %s\n' "$VERSION"
}
show_help() {
show_brand_banner
echo
printf "%s%s%s\n" "$BLUE" "USAGE" "$NC"
printf " %s%s%s [command]\n\n" "$GREEN" "mole" "$NC"
printf "%s%s%s\n" "$BLUE" "COMMANDS" "$NC"
printf " %s%-20s%s %s\n" "$GREEN" "mole" "$NC" "Interactive main menu"
printf " %s%-20s%s %s\n" "$GREEN" "mole clean" "$NC" "Deeper system cleanup"
printf " %s%-20s%s %s\n" "$GREEN" "mole clean --dry-run" "$NC" "Preview cleanup (no deletions)"
printf " %s%-20s%s %s\n" "$GREEN" "mole uninstall" "$NC" "Remove applications completely"
printf " %s%-20s%s %s\n" "$GREEN" "mole update" "$NC" "Update Mole to the latest version"
printf " %s%-20s%s %s\n" "$GREEN" "mole --version" "$NC" "Show installed version"
printf " %s%-20s%s %s\n" "$GREEN" "mole --help" "$NC" "Show this help message"
printf "\n%s%s%s\n" "$BLUE" "MORE" "$NC"
printf " https://github.com/tw93/mole\n\n"
}
# Simple update function
update_mole() {
log_info "Updating Mole..."
local installer_url="https://raw.githubusercontent.com/tw93/mole/main/install.sh"
local tmp_installer
tmp_installer="$(mktemp)" || { log_error "Failed to create temp file"; exit 1; }
# Download installer with timeout
if command -v curl >/dev/null 2>&1; then
if ! curl -fsSL --connect-timeout 10 --max-time 60 "$installer_url" -o "$tmp_installer"; then
rm -f "$tmp_installer"
log_error "Failed to download installer (network timeout or error)"
exit 1
fi
elif command -v wget >/dev/null 2>&1; then
if ! wget --timeout=10 --tries=3 -qO "$tmp_installer" "$installer_url"; then
rm -f "$tmp_installer"
log_error "Failed to download installer (network timeout or error)"
exit 1
fi
else
rm -f "$tmp_installer"
log_error "Please install curl or wget to update Mole"
exit 1
fi
chmod +x "$tmp_installer"
# Determine install directory
local mole_path
mole_path="$(command -v mole 2>/dev/null || echo "$0")"
local install_dir
install_dir="$(cd "$(dirname "$mole_path")" && pwd)"
# Run installer
if "$tmp_installer" --prefix "$install_dir" --config "$HOME/.config/mole" --update 2>/dev/null; then
log_success "Mole updated successfully"
else
log_warning "Update failed, trying reinstall..."
if "$tmp_installer" --prefix "$install_dir" --config "$HOME/.config/mole"; then
log_success "Mole reinstalled successfully"
else
rm -f "$tmp_installer"
log_error "Update failed"
exit 1
fi
fi
rm -f "$tmp_installer"
}
# Display main menu options
show_main_menu() {
local selected="${1:-1}"
local full_draw="${2:-true}"
if [[ "$full_draw" == "true" ]]; then
clear_screen
echo ""
show_brand_banner
echo ""
printf '\033[s'
else
printf '\033[u\033[0J'
fi
show_menu_option 1 "Clean System - Remove junk files and optimize" "$([[ $selected -eq 1 ]] && echo true || echo false)"
show_menu_option 2 "Uninstall Apps - Remove applications completely" "$([[ $selected -eq 2 ]] && echo true || echo false)"
show_menu_option 3 "Help & Information - Usage guide and tips" "$([[ $selected -eq 3 ]] && echo true || echo false)"
show_menu_option 4 "Exit - Close Mole" "$([[ $selected -eq 4 ]] && echo true || echo false)"
if [[ -t 0 ]]; then
echo ""
echo -e "${BLUE}↑/↓ to navigate, ENTER to select, Q to quit${NC}"
fi
}
# Interactive main menu loop
interactive_main_menu() {
maybe_show_intro() {
if [[ ! -t 1 ]]; then
return
fi
local tty_name
tty_name=$(tty 2>/dev/null || echo "")
if [[ -n "$tty_name" ]]; then
local sanitized
sanitized=$(echo "$tty_name" | tr -c '[:alnum:]_' '_')
local flag_file="/tmp/mole_intro_${sanitized}"
if [[ -f "$flag_file" ]]; then
return
fi
animate_mole_intro
touch "$flag_file" 2>/dev/null || true
else
if [[ -z "${MOLE_INTRO_SHOWN:-}" ]]; then
animate_mole_intro
export MOLE_INTRO_SHOWN=1
fi
fi
}
if [[ -t 1 ]]; then
animate_mole_intro
fi
local current_option=1
local first_draw=true
cleanup_and_exit() {
show_cursor
echo ""
echo "Thank you for using Mole!"
exit 0
}
trap cleanup_and_exit INT
hide_cursor
while true; do
show_main_menu $current_option "$first_draw"
if [[ "$first_draw" == "true" ]]; then
first_draw=false
fi
local key=$(read_key)
[[ $? -ne 0 ]] && continue
case "$key" in
"UP") ((current_option > 1)) && ((current_option--)) ;;
"DOWN") ((current_option < 4)) && ((current_option++)) ;;
"ENTER"|"$current_option")
show_cursor
case $current_option in
1)
exec "$SCRIPT_DIR/bin/clean.sh"
;;
2) exec "$SCRIPT_DIR/bin/uninstall.sh" ;;
3) clear; show_help; exit 0 ;;
4) cleanup_and_exit ;;
esac
;;
"QUIT") cleanup_and_exit ;;
[1-4])
show_cursor
case $key in
1)
exec "$SCRIPT_DIR/bin/clean.sh"
;;
2) exec "$SCRIPT_DIR/bin/uninstall.sh" ;;
3) clear; show_help; exit 0 ;;
4) cleanup_and_exit ;;
esac
;;
esac
done
}
main() {
# Check for updates (non-blocking, won't delay startup)
check_for_updates
case "${1:-""}" in
"clean")
exec "$SCRIPT_DIR/bin/clean.sh" "${@:2}"
;;
"uninstall")
exec "$SCRIPT_DIR/bin/uninstall.sh"
;;
"update")
update_mole
exit 0
;;
"help"|"--help"|"-h")
show_help
exit 0
;;
"version"|"--version"|"-V")
show_version
exit 0
;;
"")
interactive_main_menu
;;
*)
echo "Unknown command: $1"
echo "Use 'mole --help' for usage information."
exit 1
;;
esac
}
main "$@"