From d6e1a68ec483e9b89d176b986f10ad2e5a6d807d Mon Sep 17 00:00:00 2001 From: Bruno21 Date: Sat, 6 Jan 2024 07:12:56 +0100 Subject: [PATCH] 1st commit --- cleanup.sh | 687 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 687 insertions(+) create mode 100755 cleanup.sh diff --git a/cleanup.sh b/cleanup.sh new file mode 100755 index 0000000..515bf63 --- /dev/null +++ b/cleanup.sh @@ -0,0 +1,687 @@ +#!/usr/bin/env bash + +#When a query returns a non-zero status, the -e flag stops the script. It also detects errors in the currently executing script. +set -E +trap cleanup SIGINT SIGTERM ERR EXIT + +cleanup() { + trap - SIGINT SIGTERM ERR EXIT +} + +#italic="\033[3m" +#underline="\033[4m" +#ita_under="\033[3;4m" +#bgd="\033[1;4;31m" +#red="\033[1;31m" +#bold="\033[1m" +#box="\033[1;41m" +#reset="\033[0m" + +opt_cache=true +opt_log=true +opt_adobe=true +opt_chrome=false # +opt_ios_app=true +opt_ios_device=true +opt_xcode=true +opt_xcrun=true +opt_brew=false +opt_gem=false # ok +opt_npm=false # ok +opt_go=false # ok +opt_teams=true +opt_dns=true +opt_memory=true +opt_periodic=true + + +usage() { + cat <&2 -e "${1-}" + #fi +} + +die() { + local msg=$1 + local code=${2-1} # default exit status 1 + msg "$msg" + exit "$code" +} + +parse_params() { + # default values of variables set from params + update=false + + while :; do + case "${1-}" in + -h | --help) usage ;; + #-v | --verbose) set -x ;; + -d | --dry-run) dry_run=true ;; + --no-color) NO_COLOR=1 ;; + #-u | --update) update=true ;; # update flag + -n) true ;; # This is a legacy option, now default behaviour + -?*) die "Unknown option: $1" ;; + *) break ;; + esac + shift + done + + return 0 +} + +parse_params "$@" +setup_colors + +# [ -z EMPTYSTRING ] +# [ -n NONEMPTYSTRING ] + +if [ -n "$dry_run" ]; then + msg "${RED}Running dry run mode !\n${NOFORMAT}" +else + echo +fi + +_bytesToHuman() { + b=$1 + echo $b + } + +bytesToHuman() { + b=${1:-0} + d='' + s=1 + S=(Bytes {K,M,G,T,E,P,Y,Z}iB) + while ((b > 1024)); do + d="$(printf ".%02d" $((b % 1024 * 100 / 1024)))" + b=$((b / 1024)) + ((s++)) + done + + human_size="$b$d ${S[$s]}" + echo $human_size +} + +count_dry() { + #echo "count_dry" + #local dry_results + #local temp_dry_results + for path in "${path_list[@]}"; do + if [ -d "$path" ] || [ -f "$path" ]; then + #echo "$path" + temp_dry_results=$(sudo du -ck "$path" | tail -1 | awk '{ print $1 }') + #echo "$path" "$temp_dry_results" + dry_results="$((dry_results+temp_dry_results))" + fi + done + echo $dry_results +} + +remove_paths() { + if [ -z "$dry_run" ]; then + echo -e -n "Clean up $(bytesToHuman $count_section) ? (y/n) " + read -r -s -n1 clean_dry_run + if [[ $clean_dry_run = "y" ]]; then + for path in "${path_list[@]}"; do + msg "Remove $path" + #rm -rfv "$path" &>/dev/null + done + totalFree="$((totalFree+count_section))" + + fi + fi + unset path_list +} + +collect_paths() { + path_list+=("$@") +} + +# Ask for the administrator password upfront +sudo -v + +HOST=$(whoami) + +# Keep-alive sudo until `mac-cleanup.sh` has finished +while true; do + sudo -n true + sleep 60 + kill -0 "$$" || exit +done 2>/dev/null & + +# Enable extended regex +shopt -s extglob + +# Space cleaned counter +totalFree=0 + + +### Display disk free size ### + +msg "${BOLD}Free space on HDD...${NOFORMAT}\n" +oldAvailable=$(df / | tail -1 | awk '{print $4}') +msg "${BLUE}$(bytesToHuman $oldAvailable) available on /${NOFORMAT}" +echo + + +### Empty Trashes ### + +msg "${BOLD}Emptying the Trash 🗑 on all mounted volumes and the main HDD...${NOFORMAT}" + +collect_paths /Volumes/*/.Trashes/* +collect_paths ~/.Trash/* + +count_section=$(count_dry) + +msg "${BLUE}\nApprox $(bytesToHuman $count_section) of space will be cleaned up${NOFORMAT}" +remove_paths +echo "count_section $count_section" +echo "totalFree $totalFree" + + +### Empty System Cache Files ### + +if [[ $opt_cache = true ]]; then + msg "\n${BOLD}Clearing System Cache Files...${NOFORMAT}" + + collect_paths /Library/Caches/* + collect_paths /System/Library/Caches/* + collect_paths ~/Library/Caches/* + collect_paths /private/var/folders/bh/*/*/*/* + + count_section=$(count_dry) +echo -e "${RED}System cache: $count_section${NOFORMAT}" +#totalFree="$((totalFree+count_section))" + + if [ -z "$dry_run" ]; then + msg "${BLUE}\nApprox $(bytesToHuman $count_section) of space will be cleaned up${NOFORMAT}\n" + remove_paths + else + msg "${BLUE}\nApprox $(bytesToHuman $count_section) of space will be cleaned up${NOFORMAT}\n" + unset path_list + fi + +echo "totalFree $totalFree" +fi + + +### Empty System Log Files ### + +if [[ $opt_log = true ]]; then + msg "\n${BOLD}Clearing System Log Files...${NOFORMAT}" + + collect_paths /private/var/log/asl/*.asl + collect_paths /Library/Logs/DiagnosticReports/* + collect_paths /Library/Logs/CreativeCloud/* + collect_paths /Library/Logs/Adobe/* + collect_paths /Library/Logs/adobegc.log + collect_paths ~/Library/Containers/com.apple.mail/Data/Library/Logs/Mail/* + collect_paths ~/Library/Logs/CoreSimulator/* + + count_section=$(count_dry) +echo -e "${RED}System log: $count_section${NOFORMAT}" +#totalFree="$((totalFree+count_section))" + + if [ -z "$dry_run" ]; then + msg "${BLUE}\nApprox $(bytesToHuman $count_section) of space will be cleaned up${NOFORMAT}\n" + remove_paths + else + msg "${BLUE}\nApprox $(bytesToHuman $count_section) of space will be cleaned up${NOFORMAT}\n" + unset path_list + fi + +echo "totalFree $totalFree" +fi + +### Adobe Cache ### + +if [[ $opt_adobe = true ]]; then + if [ -d ~/Library/Application\ Support/Adobe/ ]; then + msg "\n${BOLD}Clearing Adobe Cache Files...${NOFORMAT}" + + collect_paths ~/Library/Application\ Support/Adobe/Common/Media\ Cache\ Files/* + count_section=$(count_dry) +echo -e "${RED}Adobe: $count_section${NOFORMAT}" + + if [ -z "$dry_run" ]; then + msg "${BLUE}\nApprox $(bytesToHuman $count_section) of space will be cleaned up${NOFORMAT}" + remove_paths + else + msg "${BLUE}\nApprox $(bytesToHuman $count_section) of space will be cleaned up${NOFORMAT}\n" + unset path_list + fi + fi + +echo "totalFree $totalFree" +fi + + +### Google Chrome Cache ### + +if [[ $opt_chrome = true ]]; then + if [ -d ~/Library/Application\ Support/Google/Chrome/ ]; then + msg "\n${BOLD}Clearing Google Chrome Cache Files...${NOFORMAT}" + + collect_paths ~/Library/Application\ Support/Google/Chrome/Default/Application\ Cache/* + count_section=$(count_dry) +echo -e "${RED}Chrome: $count_section${NOFORMAT}" + + if [ -z "$dry_run" ]; then + msg "${BLUE}\nApprox $(bytesToHuman $count_section) of space will be cleaned up${NOFORMAT}" + remove_paths + else + msg "${BLUE}\nApprox $(bytesToHuman $count_section) of space will be cleaned up${NOFORMAT}\n" + unset path_list + fi + fi +fi + + +### iOS Applications ### + +if [[ $opt_ios_app = true ]]; then + if [ -d ~/Music/iTunes/ ]; then + msg "\n${BOLD}Cleaning up iOS Applications...${NOFORMAT}" + + collect_paths ~/Music/iTunes/iTunes\ Media/Mobile\ Applications/* + count_section=$(count_dry) +echo -e "${RED}iOS app: $count_section${NOFORMAT}" + + if [ -z "$dry_run" ]; then + msg "${BLUE}\nApprox $(bytesToHuman $count_section) of space will be cleaned up${NOFORMAT}" + remove_paths + else + msg "${BLUE}\nApprox $(bytesToHuman $count_section) of space will be cleaned up${NOFORMAT}\n" + unset path_list + fi + fi + +echo "totalFree $totalFree" +fi + + +### iOS Device Backups ### + +if [[ $opt_ios_device = true ]]; then + + msg "\n${BOLD}Removing iOS Device Backups...${NOFORMAT}" + + collect_paths ~/Library/Application\ Support/MobileSync/Backup/* + count_section=$(count_dry) +echo -e "${RED}iOS device: $count_section${NOFORMAT}" + + if [ -z "$dry_run" ]; then + msg "${BLUE}\nApprox $(bytesToHuman $count_section) of space will be cleaned up${NOFORMAT}" + remove_paths + else + msg "${BLUE}\nApprox $(bytesToHuman $count_section) of space will be cleaned up${NOFORMAT}\n" + unset path_list + fi + +echo "totalFree $totalFree" +fi + + +### Xcode ### + +if [[ $opt_xcode = true ]]; then + if [ -d ~/Library/Developer/Xcode/ ]; then + + msg "\n${BOLD}Cleaning up XCode Derived Data and Archives...${NOFORMAT}" + + collect_paths ~/Library/Developer/Xcode/DerivedData/* + collect_paths ~/Library/Developer/Xcode/Archives/* + collect_paths ~/Library/Developer/Xcode/iOS Device Logs/* + + count_section=$(count_dry) +echo -e "${RED}xcode: $count_section${NOFORMAT}" + + if [ -z "$dry_run" ]; then + msg "${BLUE}\nApprox $(bytesToHuman $count_section) of space will be cleaned up${NOFORMAT}" + remove_paths + else + msg "${BLUE}\nApprox $(bytesToHuman $count_section) of space will be cleaned up${NOFORMAT}\n" + unset path_list + fi + fi + +echo "totalFree $totalFree" +fi + + +# Xcrun + +if [[ $opt_xcrun = true ]]; then + + if type "xcrun" &>/dev/null; then + msg "\n${BOLD}Cleaning up iOS Simulators...${NOFORMAT}\n" + if [ -z "$dry_run" ]; then + + # List available devices, device types, runtimes, or device pairs. + # xcrun simctl list + + # Shutdown a device. ( | all) + # Specifying all will shut down all running devices + # xcrun simctl shutdown all &>/dev/null + + # Erase a device's contents and settings. ([... ] | all) + # Specifying all will erase all existing devices. + # xcrun simctl erase all &>/dev/null + + echo -e "Running ${ITALIC}xcrun simctl delete unavailable${NOFORMAT}" + # Delete specified devices, unavailable devices, or all devices. ([... ] | unavailable | all) + # Specifying unavailable will delete devices that are not supported by the current Xcode SDK. + # xcrun simctl delete unavailable + else + collect_paths ~/Library/Developer/CoreSimulator/Devices/*/data/!(Library|var|tmp|Media) + collect_paths /Users/wah/Library/Developer/CoreSimulator/Devices/*/data/Library/!(PreferencesCaches|Caches|AddressBook) + collect_paths ~/Library/Developer/CoreSimulator/Devices/*/data/Library/Caches/* + collect_paths ~/Library/Developer/CoreSimulator/Devices/*/data/Library/AddressBook/AddressBook* + echo ${path_list[@]} + count_section=$(count_dry) +echo -e "${RED}xcrcun: $count_section${NOFORMAT}" + unset path_list + fi + fi +fi + + +### Brew ### + +if [[ $opt_brew = true ]]; then + + if type "brew" &>/dev/null; then + msg "\n${BOLD}Cleaning up brew cache...${NOFORMAT}\n" + collect_paths "$(brew --cache)" + if [ -z "$dry_run" ]; then + + # Remove stale lock files and outdated downloads for all formulae and casks, and remove old versions of installed formulae. + # If arguments are specified, only do this for the given formulae and casks. Removes all downloads more than 120 days old. + # This can be adjusted with HOMEBREW_CLEANUP_MAX_AGE_DAYS. + + # -s: Scrub the cache, including downloads for even the latest versions. Note that downloads for any installed formulae or + # casks will still not be deleted. If you want to delete those too: rm -rf "$(brew --cache)" + + echo -e "Running ${ITALIC}brew cleanup -s${NOFORMAT}" + # brew cleanup -s &>/dev/null + free=$(brew cleanup -s --dry-run | grep -o -E " [0-9]{1,3}(B|KB|MB|GB) ") + + msg "${BLUE}\nApprox $free of space has been cleaned up${NOFORMAT}\n" + + echo -e "Running ${ITALIC}brew autoremove${NOFORMAT}" + + # Uninstall formulae that were only installed as a dependency of another formula and are now no longer needed. + brew autoremove --dry-run + + # Migrate tapped formulae from symlink-based to directory-based structure. + # brew tap --repair &>/dev/null + + else + echo -e "Running ${ITALIC}brew cleanup -s --dry-run${NOFORMAT}" + free=$(brew cleanup -s --dry-run | grep -o -E " [0-9]{1,3}(B|KB|MB|GB) ") + + msg "${BLUE}\nApprox $free of space will be cleaned up${NOFORMAT}\n" + + echo -e "Running ${ITALIC}brew autoremove --dry-run${NOFORMAT}" + + brew autoremove --dry-run + + fi + unset path_list + fi + +fi + + +### gem ### + +# The cleanup command removes old versions of gems from GEM_HOME that are not required to meet a dependency. +# If a gem is installed elsewhere in GEM_PATH the cleanup command won't delete it. +# If no gems are named all gems in GEM_HOME are cleaned. + +if [[ $opt_gem = true ]]; then + + if type "gem" &>/dev/null; then # TODO add count_dry + msg "\n${BOLD}Cleaning up any old versions of gems...${NOFORMAT}" + if [ -z "$dry_run" ]; then + echo -e "Running ${ITALIC}gem cleanup${NOFORMAT}" + #gem cleanup &>/dev/null + else + echo -e "Running ${ITALIC}gem cleanup -V --dry-run${NOFORMAT}" + gem cleanup -V --dry-run + fi + fi + +fi + + +### npm ### + +# prune: This command removes "extraneous" packages. If a package name is provided, then only packages matching one of the supplied names are removed. +# Extraneous packages are those present in the node_modules folder that are not listed as any package's dependency list. +# clean: Delete all data out of the cache folder. Note that this is typically unnecessary, as npm's cache is self-healing and resistant to data corruption issues. + +if [[ $opt_npm = true ]]; then + + if type "npm" &>/dev/null; then + msg "\n${BOLD}Cleaning up npm cache...${NOFORMAT}" + collect_paths ~/.npm/_cacache/* + count_section=$(count_dry) +echo -e "${RED}npm: $count_section${NOFORMAT}" + + if [ -z "$dry_run" ]; then + echo -e "Running ${ITALIC}npm cache clean --force${NOFORMAT}" + #npm cache clean --force &>/dev/null + msg "${BLUE}\nApprox $(bytesToHuman $count_section) of space has been cleaned up${NOFORMAT}." + + echo -e "Running ${ITALIC}npm prune${NOFORMAT}" + npm_prune=$(npm prune) + [[ ! "$npm_prune" =~ "up to date in" ]] && echo "$npm_prune" + else + # npm cache clean --dry-run doesn't exist + msg "${BLUE}Approx $(bytesToHuman $count_section) of space will be cleaned up by running ${ITALIC}npm cache clean --force${NOFORMAT}" + + echo -e "Running ${ITALIC}npm prune --dry-run${NOFORMAT}" + npm_prune=$(npm prune --dry-run) + [[ ! "$npm_prune" =~ "up to date in" ]] && echo "$npm_prune" + fi + + unset path_list + totalFree="$((totalFree+count_section))" +echo -e "${RED}TOTAL: $totalFree${NOFORMAT}" + fi + +fi + +# Docker + +# Pyenv + +# yarn + +# pnpm + +# pod + +### Cargo ### + +# https://blog.rust-lang.org/2023/12/11/cargo-cache-cleaning.html + +# https://github.com/matthiaskrgr/cargo-cache +# cargo cache --autoclean +# cargo cache --dry-run +# Size changed 842.71 MB => 660.87 MB (-181.84 MB, -21.57%) + + +# Remove artifacts from the target directory that Cargo has generated in the past. +# With no options, cargo clean will delete the entire target directory. +# When no packages are selected, all packages and all dependencies in the workspace are cleaned. +# cargo clean --dry-run +# cargo clean gc + +# Remove one or more dependencies from a Cargo.toml manifest. +# cargo remove --dry-run + +### go ### + +# ~/Library/Caches/go-build +# 1 This directory holds cached build artifacts from the Go build system. +# 2 Run "go clean -cache" if the directory is getting too large. The -cache flag causes clean to remove the entire go build cache. +# 3 Run "go clean -fuzzcache" to delete the fuzz cache. The -fuzzcache flag causes clean to remove files stored in the Go build +# cache for fuzz testing. The fuzzing engine caches files that expand code coverage, so removing them may make fuzzing less effective until +# new inputs are found that provide the same coverage. These files are distinct from those stored in testdata directory; clean does not remove +# those files. +# 4 The -modcache flag causes clean to remove the entire module download cache, including unpacked source code of versioned dependencies. + + +# GOCACHE='/Users/bruno/Library/Caches/go-build' +# GOMODCACHE='/Users/bruno/go/pkg/mod' + +# /Users/bruno/go/pkg/mod/cache + +if [[ $opt_go = true ]]; then + + if type "go" &>/dev/null; then + msg "\n${BOLD}Clearing Go module cache...${NOFORMAT}" + go_env=$(go env) + go_cache=$(echo "$go_env" | grep GOCACHE | awk -F"=" '{print $2}' | tr -d "'") + collect_paths "$go_cache" + if [ -n "$GOPATH" ]; then + collect_paths "$GOPATH/pkg/mod" + else + go_modcache=$(echo "$go_env" | grep GOMODCACHE | awk -F"=" '{print $2}' | tr -d "'") + collect_paths "$go_modcache" + fi + count_section=$(count_dry) +echo -e "${RED}go: $count_section{NOFORMAT}" + + if [ -z "$dry_run" ]; then + echo -e "Remove the entire module download cache. Running ${ITALIC}go clean -modcache${NOFORMAT}" + go clean -modcache &>/dev/null + + echo -e "Remove the entire go build cache. Running ${ITALIC}go clean -cache${NOFORMAT}" + go clean -cache &>/dev/null + msg "${BLUE}\nApprox $(bytesToHuman $count_section) of space has been cleaned up${NOFORMAT}" + else + msg "\n${BLUE}Approx $(bytesToHuman $count_section) of space will be cleaned up by running ${ITALIC}go clean -modcache${NOFORMAT}${BLUE} and ${ITALIC}go clean -cache${NOFORMAT}" + fi + + unset path_list + totalFree="$((totalFree+count_section))" +echo -e "${RED}TOTAL: $totalFree{NOFORMAT}" + fi +fi + + +### Deletes all Microsoft Teams Caches and resets it to default - can fix also some performance issues ### +# -Astro + +if [[ $opt_teams = true ]]; then + if [ -d ~/Library/Application\ Support/Microsoft/Teams ]; then + msg "\n${BOLD}Deleting Microsoft Teams logs and caches...${NOFORMAT}" + + #collect_paths ~/Library/Application\ Support/Microsoft/Teams/IndexedDB + #collect_paths ~/Library/Application\ Support/Microsoft/Teams/Cache + #collect_paths ~/Library/Application\ Support/Microsoft/Teams/Application\ Cache + #collect_paths ~/Library/Application\ Support/Microsoft/Teams/Code\ Cache + #collect_paths ~/Library/Application\ Support/Microsoft/Teams/blob_storage + #collect_paths ~/Library/Application\ Support/Microsoft/Teams/databases + #collect_paths ~/Library/Application\ Support/Microsoft/Teams/gpucache + #collect_paths ~/Library/Application\ Support/Microsoft/Teams/Local\ Storage + #collect_paths ~/Library/Application\ Support/Microsoft/Teams/tmp + #collect_paths ~/Library/Application\ Support/Microsoft/Teams/*logs*.txt + #collect_paths ~/Library/Application\ Support/Microsoft/Teams/watchdog + #collect_paths ~/Library/Application\ Support/Microsoft/Teams/*watchdog*.json + + collect_paths ~/Library/Group\ Containers/UBF8T346G9.com.microsoft.teams/* # 776 + collect_paths ~/Library/Containers/com.microsoft.teams2/* # 26872 + # ~/Library/Containers/com.microsoft.teams2.launcher/ + # ~/Library/Containers/com.microsoft.teams2.notificationcenter/ + + collect_paths ~/Library/Application\ Support/Microsoft/Teams/* #977048 + [ -d ~/Library/Logs/Microsoft\ Teams/ ] && collect_paths ~/Library/Logs/Microsoft\ Teams/* # / + [ -d ~/Library/Logs/Microsoft\ Teams\ Helper/ ] && collect_paths ~/Library/Logs/Microsoft\ Teams\ Helper/* # / + [ -d ~/Library/Logs/Microsoft\ Teams\ Helper\ \(Renderer\)/ ] && collect_paths ~/Library/Logs/Microsoft\ Teams\ Helper\ \(Renderer\)/* + count_section=$(count_dry) +echo -e "${RED}teams: $count_section${NOFORMAT}" + + if [ -z "$dry_run" ]; then + # QUIT Teams + /usr/bin/pkill -9 'Teams' &>/dev/null + msg "${BLUE}\nApprox $(bytesToHuman $count_section) of space will be cleaned up${NOFORMAT}" + remove_paths + else + msg "${BLUE}\nApprox $(bytesToHuman $count_section) of space will be cleaned up${NOFORMAT}" + unset path_list + fi + + totalFree="$((totalFree+count_section))" +echo -e "${RED}TOTAL: $totalFree${NOFORMAT}" + fi +fi + + +if [[ $opt_dns = true ]]; then + + if [ -z "$dry_run" ]; then + msg "\n${BOLD}Cleaning up DNS cache...${NOFORMAT}" + echo -e "Running ${ITALIC}sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder${NOFORMAT}" + #sudo dscacheutil -flushcache &>/dev/null + #sudo killall -HUP mDNSResponder &>/dev/null + fi +fi + + +if [[ $opt_memory = true ]]; then + + if [ -z "$dry_run" ]; then + msg "\n${BOLD}Purging inactive memory...${NOFORMAT}" + echo -e "Running ${ITALIC}sudo purge${NOFORMAT}" + # force disk cache to be purged (flushed and emptied) + #sudo purge &>/dev/null + fi +fi + + +if [[ $opt_periodic = true ]]; then + + if [ -z "$dry_run" ]; then + msg "\n${BOLD}Running the maintenance scripts...${NOFORMAT}" + echo -e "Running ${ITALIC}sudo periodic daily weekly monthly${NOFORMAT}" + #sudo periodic daily weekly monthly + fi +fi + + +# End + +msg "${GREEN}\nSuccess!${NOFORMAT}" +msg "${BLUE}\nApprox $(bytesToHuman $totalFree) of space has been cleaned up${NOFORMAT}" + +newAvailable=$(df / | tail -1 | awk '{print $4}') +msg "${BLUE}$(bytesToHuman $newAvailable) available on /${NOFORMAT}"