3030# --- Global Variables ---
3131SCRIPT_VERSION=" 1.2.0"
3232GITHUB_REPO=" https://github.com/jemishavasoya/dev-cleaner"
33+ DRY_RUN=false
3334
3435# Check if FLUTTER_SEARCH_DIR is already set as environment variable
3536if [ -z " ${FLUTTER_SEARCH_DIR} " ]; then
@@ -86,37 +87,146 @@ get_disk_space() {
8687 df -h . | awk ' NR==2 {print $4}'
8788}
8889
90+ # Dry-run aware file/directory removal
91+ # Usage: safe_rm [-r] <path> [<path> ...]
92+ safe_rm () {
93+ local recursive=" "
94+ local paths=()
95+
96+ # Parse arguments
97+ while [[ $# -gt 0 ]]; do
98+ case " $1 " in
99+ -r|-rf|-fr)
100+ recursive=" -rf"
101+ shift
102+ ;;
103+ * )
104+ paths+=(" $1 " )
105+ shift
106+ ;;
107+ esac
108+ done
109+
110+ for path in " ${paths[@]} " ; do
111+ # Expand globs and handle paths
112+ local expanded_paths=()
113+ # Use nullglob to handle non-matching patterns
114+ shopt -s nullglob
115+ if [[ " $path " == * \* * || " $path " == * \? * ]]; then
116+ expanded_paths=($path )
117+ else
118+ expanded_paths=(" $path " )
119+ fi
120+ shopt -u nullglob
121+
122+ for expanded_path in " ${expanded_paths[@]} " ; do
123+ if [[ -e " $expanded_path " ]]; then
124+ if $DRY_RUN ; then
125+ local size=" "
126+ if [[ -d " $expanded_path " ]]; then
127+ size=$( du -sh " $expanded_path " 2> /dev/null | cut -f1)
128+ echo -e " ${YELLOW} [DRY-RUN] Would delete directory: ${expanded_path} (${size:- unknown size} )${NC} "
129+ else
130+ size=$( du -h " $expanded_path " 2> /dev/null | cut -f1)
131+ echo -e " ${YELLOW} [DRY-RUN] Would delete file: ${expanded_path} (${size:- unknown size} )${NC} "
132+ fi
133+ else
134+ if [[ -n " $recursive " ]]; then
135+ rm -rf " $expanded_path "
136+ else
137+ rm -f " $expanded_path "
138+ fi
139+ fi
140+ fi
141+ done
142+ done
143+ }
144+
145+ # Dry-run aware sudo file/directory removal
146+ # Usage: safe_sudo_rm [-r] <path> [<path> ...]
147+ safe_sudo_rm () {
148+ local recursive=" "
149+ local paths=()
150+
151+ # Parse arguments
152+ while [[ $# -gt 0 ]]; do
153+ case " $1 " in
154+ -r|-rf|-fr)
155+ recursive=" -rf"
156+ shift
157+ ;;
158+ * )
159+ paths+=(" $1 " )
160+ shift
161+ ;;
162+ esac
163+ done
164+
165+ for path in " ${paths[@]} " ; do
166+ # Expand globs and handle paths
167+ local expanded_paths=()
168+ shopt -s nullglob
169+ if [[ " $path " == * \* * || " $path " == * \? * ]]; then
170+ expanded_paths=($path )
171+ else
172+ expanded_paths=(" $path " )
173+ fi
174+ shopt -u nullglob
175+
176+ for expanded_path in " ${expanded_paths[@]} " ; do
177+ if [[ -e " $expanded_path " ]] || sudo test -e " $expanded_path " 2> /dev/null; then
178+ if $DRY_RUN ; then
179+ local size=" "
180+ if [[ -d " $expanded_path " ]] || sudo test -d " $expanded_path " 2> /dev/null; then
181+ size=$( sudo du -sh " $expanded_path " 2> /dev/null | cut -f1)
182+ echo -e " ${YELLOW} [DRY-RUN] Would delete directory (sudo): ${expanded_path} (${size:- unknown size} )${NC} "
183+ else
184+ size=$( sudo du -h " $expanded_path " 2> /dev/null | cut -f1)
185+ echo -e " ${YELLOW} [DRY-RUN] Would delete file (sudo): ${expanded_path} (${size:- unknown size} )${NC} "
186+ fi
187+ else
188+ if [[ -n " $recursive " ]]; then
189+ sudo rm -rf " $expanded_path "
190+ else
191+ sudo rm -f " $expanded_path "
192+ fi
193+ fi
194+ fi
195+ done
196+ done
197+ }
198+
89199# --- Cleanup Functions ---
90200cleanup_xcode () {
91201 print_item " ✓" " ${GREEN} " " Clearing Xcode DerivedData..."
92- rm -rf ~ /Library/Developer/Xcode/DerivedData/
202+ safe_rm -rf ~ /Library/Developer/Xcode/DerivedData/
93203 print_item " ✓" " ${GREEN} " " Removing old Simulator devices..."
94- rm -rf ~ /Library/Developer/CoreSimulator/Devices/
204+ safe_rm -rf ~ /Library/Developer/CoreSimulator/Devices/
95205 print_item " ✓" " ${GREEN} " " Removing old device support files..."
96- rm -rf ~ /Library/Developer/Xcode/iOS\ DeviceSupport/
206+ safe_rm -rf ~ /Library/Developer/Xcode/iOS\ DeviceSupport/
97207 print_item " ✓" " ${GREEN} " " Removing Xcode caches..."
98- rm -rf ~ /Library/Caches/com.apple.dt.Xcode/
208+ safe_rm -rf ~ /Library/Caches/com.apple.dt.Xcode/
99209 print_item " ✓" " ${GREEN} " " Removing Xcode Archives..."
100- rm -rf ~ /Library/Developer/Xcode/Archives/
210+ safe_rm -rf ~ /Library/Developer/Xcode/Archives/
101211 print_item " ✓" " ${GREEN} " " Removing Xcode build Products..."
102- rm -rf ~ /Library/Developer/Xcode/Products/
212+ safe_rm -rf ~ /Library/Developer/Xcode/Products/
103213 print_item " ✓" " ${GREEN} " " Removing Xcode DocumentationCache..."
104- rm -rf ~ /Library/Developer/Xcode/DocumentationCache/
214+ safe_rm -rf ~ /Library/Developer/Xcode/DocumentationCache/
105215 print_item " ✓" " ${GREEN} " " Cleaning CoreDevice cache..."
106- rm -rf ~ /Library/Containers/com.apple.CoreDevice.CoreDeviceService/Data/Library/Caches/*
216+ safe_rm -rf ~ /Library/Containers/com.apple.CoreDevice.CoreDeviceService/Data/Library/Caches/*
107217}
108218
109219cleanup_android () {
110220 if [ -d " $HOME /.gradle" ]; then
111221 print_item " ✓" " ${GREEN} " " Cleaning Gradle caches..."
112- rm -rf ~ /.gradle/caches/
113- rm -rf ~ /.gradle/daemon/
222+ safe_rm -rf ~ /.gradle/caches/
223+ safe_rm -rf ~ /.gradle/daemon/
114224 else
115225 print_item " ✕" " ${YELLOW} " " Gradle directory not found. Skipping."
116226 fi
117227 print_item " ✓" " ${GREEN} " " Cleaning Android Studio caches..."
118- rm -rf ~ /Library/Caches/Google/AndroidStudio*
119- rm -rf ~ /Library/Caches/JetBrains/AndroidStudio*
228+ safe_rm -rf ~ /Library/Caches/Google/AndroidStudio*
229+ safe_rm -rf ~ /Library/Caches/JetBrains/AndroidStudio*
120230}
121231
122232cleanup_android_sdk () {
@@ -125,16 +235,28 @@ cleanup_android_sdk() {
125235 # Keep only latest 2 versions of build-tools
126236 if [ -d " $HOME /Library/Android/sdk/build-tools" ]; then
127237 cd " $HOME /Library/Android/sdk/build-tools" 2> /dev/null || return
128- ls -t | tail -n +3 | xargs -I {} rm -rf {}
238+ if $DRY_RUN ; then
239+ ls -t | tail -n +3 | while read -r dir; do
240+ echo -e " ${YELLOW} [DRY-RUN] Would delete: $HOME /Library/Android/sdk/build-tools/$dir ${NC} "
241+ done
242+ else
243+ ls -t | tail -n +3 | xargs -I {} rm -rf {}
244+ fi
129245 fi
130246
131247 print_item " ✓" " ${GREEN} " " Cleaning old Android platform-tools..."
132- rm -rf ~ /Library/Android/sdk/.temp 2> /dev/null || true
248+ safe_rm -rf ~ /Library/Android/sdk/.temp
133249
134250 # For Apple Silicon Macs, remove x86 emulator images if they exist
135251 if [ " $( uname -m) " = " arm64" ]; then
136252 print_item " ✓" " ${GREEN} " " Removing x86 emulator images (ARM Mac detected)..."
137- find ~ /Library/Android/sdk/system-images -type d -name " x86" -exec rm -rf {} + 2> /dev/null || true
253+ if $DRY_RUN ; then
254+ find ~ /Library/Android/sdk/system-images -type d -name " x86" 2> /dev/null | while read -r dir; do
255+ echo -e " ${YELLOW} [DRY-RUN] Would delete: $dir ${NC} "
256+ done
257+ else
258+ find ~ /Library/Android/sdk/system-images -type d -name " x86" -exec rm -rf {} + 2> /dev/null || true
259+ fi
138260 fi
139261 else
140262 print_item " ✕" " ${YELLOW} " " Android SDK not found. Skipping."
@@ -447,6 +569,7 @@ Usage: $0 [OPTIONS]
447569Options:
448570 -h, --help Show this help message
449571 -v, --version Show version information
572+ --dry-run Show what would be deleted without actually removing files
450573 --flutter-dir PATH Set custom directory for Flutter cleanup (default: current directory)
451574 Example: $0 --flutter-dir ~/Projects
452575
@@ -456,6 +579,7 @@ Command-line Flutter cleanup:
456579
457580Examples:
458581 $0 # Run interactive menu (searches current directory for Flutter projects)
582+ $0 --dry-run # Preview what would be deleted without removing anything
459583 $0 --flutter-dir ~/Development # Run with custom Flutter search directory
460584 $0 --flutter-dir ~/Projects/Flutter # Search only in specific Flutter projects folder
461585
@@ -602,9 +726,14 @@ main_loop() {
602726
603727 local final_free_space=$( get_disk_space)
604728 echo " "
605- echo -e " ${GREEN} ✅ Cleanup task(s) completed!${NC} "
606- echo -e " ${BLUE} Disk space before: ${initial_free_space}${NC} "
607- echo -e " ${BLUE} Disk space after: ${final_free_space}${NC} "
729+ if $DRY_RUN ; then
730+ echo -e " ${CYAN} 🔍 Dry-run analysis completed!${NC} "
731+ echo -e " ${CYAN} No files were deleted. Run without --dry-run to perform actual cleanup.${NC} "
732+ else
733+ echo -e " ${GREEN} ✅ Cleanup task(s) completed!${NC} "
734+ echo -e " ${BLUE} Disk space before: ${initial_free_space}${NC} "
735+ echo -e " ${BLUE} Disk space after: ${final_free_space}${NC} "
736+ fi
608737 echo " "
609738 read -p " Press Enter to return to the menu..."
610739 done
@@ -627,6 +756,10 @@ while [[ $# -gt 0 ]]; do
627756 echo " Repository: ${GITHUB_REPO} "
628757 exit 0
629758 ;;
759+ --dry-run)
760+ DRY_RUN=true
761+ shift
762+ ;;
630763 --flutter-dir)
631764 if [ -n " $2 " ] && [ " ${2: 0: 1} " != " -" ]; then
632765 # Expand ~ to home directory
657790# --- Initial check for user confirmation before starting the interactive menu ---
658791clear
659792echo -e " ${RED} --- 🚀 Dev Cleanup Utility ---${NC} "
660- echo " This script will permanently delete cache files from your system."
661- echo " Review the options carefully before proceeding."
793+ if $DRY_RUN ; then
794+ echo -e " ${CYAN}${BOLD} 🔍 DRY-RUN MODE ENABLED${NC} "
795+ echo -e " ${CYAN} This will show what would be deleted without actually removing any files.${NC} "
796+ else
797+ echo " This script will permanently delete cache files from your system."
798+ echo " Review the options carefully before proceeding."
799+ fi
662800echo " "
663801
664802# Report Flutter search directory and its source
@@ -678,10 +816,16 @@ else
678816 echo " "
679817fi
680818
681- echo -e " ${YELLOW} ⚠️ This action is IRREVERSIBLE for deleted files. ⚠️${NC} "
682- echo -e " ${YELLOW} Please CLOSE all development applications (Xcode, Android Studio, VSCode, etc.) before running.${NC} "
683- echo " "
684- read -p " Are you sure you want to start the cleanup utility? (y/N): " initial_confirm
819+ if $DRY_RUN ; then
820+ echo -e " ${GREEN} ✓ Safe to run: No files will be modified in dry-run mode.${NC} "
821+ echo " "
822+ read -p " Start dry-run analysis? (y/N): " initial_confirm
823+ else
824+ echo -e " ${YELLOW} ⚠️ This action is IRREVERSIBLE for deleted files. ⚠️${NC} "
825+ echo -e " ${YELLOW} Please CLOSE all development applications (Xcode, Android Studio, VSCode, etc.) before running.${NC} "
826+ echo " "
827+ read -p " Are you sure you want to start the cleanup utility? (y/N): " initial_confirm
828+ fi
685829if [[ " $initial_confirm " != " y" && " $initial_confirm " != " Y" ]]; then
686830 echo " Cleanup utility cancelled."
687831 exit 0
0 commit comments