Skip to content

Commit 8699d08

Browse files
Merge pull request #31 from njg7194/feat/dry-run-mode
feat: add --dry-run mode for safe preview of cleanup operations
2 parents e8515b7 + eaab553 commit 8699d08

1 file changed

Lines changed: 168 additions & 24 deletions

File tree

dev-cleaner.sh

Lines changed: 168 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ fi
3030
# --- Global Variables ---
3131
SCRIPT_VERSION="1.2.0"
3232
GITHUB_REPO="https://github.com/jemishavasoya/dev-cleaner"
33+
DRY_RUN=false
3334

3435
# Check if FLUTTER_SEARCH_DIR is already set as environment variable
3536
if [ -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 ---
90200
cleanup_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

109219
cleanup_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

122232
cleanup_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]
447569
Options:
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
457580
Examples:
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
@@ -657,8 +790,13 @@ fi
657790
# --- Initial check for user confirmation before starting the interactive menu ---
658791
clear
659792
echo -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
662800
echo ""
663801

664802
# Report Flutter search directory and its source
@@ -678,10 +816,16 @@ else
678816
echo ""
679817
fi
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
685829
if [[ "$initial_confirm" != "y" && "$initial_confirm" != "Y" ]]; then
686830
echo "Cleanup utility cancelled."
687831
exit 0

0 commit comments

Comments
 (0)