mirror of
https://github.com/tw93/Mole.git
synced 2026-03-22 17:55:08 +00:00
Add dry-run support across destructive commands (#516)
* chore: update contributors [skip ci] * Add dry-run support across destructive commands Implement dry-run for uninstall, purge, installer, touchid, completion, and remove flows.\nGuard side effects in uninstall path (launchctl, defaults writes, kill/brew actions), update help/README, and add coverage in CLI/Bats tests.\n\nValidation: ./scripts/check.sh and ./scripts/test.sh (452 tests, 0 failures, 8 skipped). * test(purge): keep dev-compatible purge coverage --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Tw93 <hitw93@gmail.com>
This commit is contained in:
@@ -32,8 +32,33 @@ emit_fish_completions() {
|
||||
printf 'complete -c %s -n "not __fish_mole_no_subcommand" -a fish -d "generate fish completion" -n "__fish_see_subcommand_path completion"\n' "$cmd"
|
||||
}
|
||||
|
||||
DRY_RUN_MODE=false
|
||||
if [[ $# -gt 0 ]]; then
|
||||
normalized_args=()
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
"--dry-run" | "-n")
|
||||
DRY_RUN_MODE=true
|
||||
;;
|
||||
*)
|
||||
normalized_args+=("$arg")
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [[ ${#normalized_args[@]} -gt 0 ]]; then
|
||||
set -- "${normalized_args[@]}"
|
||||
else
|
||||
set --
|
||||
fi
|
||||
fi
|
||||
|
||||
# Auto-install mode when run without arguments
|
||||
if [[ $# -eq 0 ]]; then
|
||||
if [[ "$DRY_RUN_MODE" == "true" ]]; then
|
||||
echo -e "${YELLOW}${ICON_DRY_RUN} DRY RUN MODE${NC}, shell config files will not be modified"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Detect current shell
|
||||
current_shell="${SHELL##*/}"
|
||||
if [[ -z "$current_shell" ]]; then
|
||||
@@ -73,16 +98,21 @@ if [[ $# -eq 0 ]]; then
|
||||
|
||||
if [[ -z "$completion_name" ]]; then
|
||||
if [[ -f "$config_file" ]] && grep -Eq "(^# Mole shell completion$|(mole|mo)[[:space:]]+completion)" "$config_file" 2> /dev/null; then
|
||||
original_mode=""
|
||||
original_mode="$(stat -f '%Mp%Lp' "$config_file" 2> /dev/null || true)"
|
||||
temp_file="$(mktemp)"
|
||||
grep -Ev "(^# Mole shell completion$|(mole|mo)[[:space:]]+completion)" "$config_file" > "$temp_file" || true
|
||||
mv "$temp_file" "$config_file"
|
||||
if [[ -n "$original_mode" ]]; then
|
||||
chmod "$original_mode" "$config_file" 2> /dev/null || true
|
||||
if [[ "$DRY_RUN_MODE" == "true" ]]; then
|
||||
echo -e "${GRAY}${ICON_REVIEW} [DRY RUN] Would remove stale completion entries from $config_file${NC}"
|
||||
echo ""
|
||||
else
|
||||
original_mode=""
|
||||
original_mode="$(stat -f '%Mp%Lp' "$config_file" 2> /dev/null || true)"
|
||||
temp_file="$(mktemp)"
|
||||
grep -Ev "(^# Mole shell completion$|(mole|mo)[[:space:]]+completion)" "$config_file" > "$temp_file" || true
|
||||
mv "$temp_file" "$config_file"
|
||||
if [[ -n "$original_mode" ]]; then
|
||||
chmod "$original_mode" "$config_file" 2> /dev/null || true
|
||||
fi
|
||||
echo -e "${GREEN}${ICON_SUCCESS}${NC} Removed stale completion entries from $config_file"
|
||||
echo ""
|
||||
fi
|
||||
echo -e "${GREEN}${ICON_SUCCESS}${NC} Removed stale completion entries from $config_file"
|
||||
echo ""
|
||||
fi
|
||||
log_error "mole not found in PATH, install Mole before enabling completion"
|
||||
exit 1
|
||||
@@ -90,6 +120,12 @@ if [[ $# -eq 0 ]]; then
|
||||
|
||||
# Check if already installed and normalize to latest line
|
||||
if [[ -f "$config_file" ]] && grep -Eq "(mole|mo)[[:space:]]+completion" "$config_file" 2> /dev/null; then
|
||||
if [[ "$DRY_RUN_MODE" == "true" ]]; then
|
||||
echo -e "${GRAY}${ICON_REVIEW} [DRY RUN] Would normalize completion entry in $config_file${NC}"
|
||||
echo ""
|
||||
exit 0
|
||||
fi
|
||||
|
||||
original_mode=""
|
||||
original_mode="$(stat -f '%Mp%Lp' "$config_file" 2> /dev/null || true)"
|
||||
temp_file="$(mktemp)"
|
||||
@@ -114,6 +150,11 @@ if [[ $# -eq 0 ]]; then
|
||||
echo -e "${GRAY}Will add to ${config_file}:${NC}"
|
||||
echo " $completion_line"
|
||||
echo ""
|
||||
if [[ "$DRY_RUN_MODE" == "true" ]]; then
|
||||
echo -e "${GREEN}${ICON_SUCCESS}${NC} Dry run complete, no changes made"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo -ne "${PURPLE}${ICON_ARROW}${NC} Enable completion for ${GREEN}${current_shell}${NC}? ${GRAY}Enter confirm / Q cancel${NC}: "
|
||||
IFS= read -r -s -n1 key || key=""
|
||||
drain_pending_input
|
||||
@@ -227,6 +268,7 @@ Setup shell tab completion for mole and mo commands.
|
||||
|
||||
Auto-install:
|
||||
mole completion # Auto-detect shell and install
|
||||
mole completion --dry-run # Preview config changes without writing files
|
||||
|
||||
Manual install:
|
||||
mole completion bash # Generate bash completion script
|
||||
|
||||
@@ -650,13 +650,22 @@ perform_installers() {
|
||||
show_summary() {
|
||||
local summary_heading="Installers cleaned"
|
||||
local -a summary_details=()
|
||||
local dry_run_mode="${MOLE_DRY_RUN:-0}"
|
||||
|
||||
if [[ "$dry_run_mode" == "1" ]]; then
|
||||
summary_heading="Dry run complete - no changes made"
|
||||
fi
|
||||
|
||||
if [[ $total_deleted -gt 0 ]]; then
|
||||
local freed_mb
|
||||
freed_mb=$(echo "$total_size_freed_kb" | awk '{printf "%.2f", $1/1024}')
|
||||
|
||||
summary_details+=("Removed ${GREEN}$total_deleted${NC} installers, freed ${GREEN}${freed_mb}MB${NC}")
|
||||
summary_details+=("Your Mac is cleaner now!")
|
||||
if [[ "$dry_run_mode" == "1" ]]; then
|
||||
summary_details+=("Would remove ${GREEN}$total_deleted${NC} installers, free ${GREEN}${freed_mb}MB${NC}")
|
||||
else
|
||||
summary_details+=("Removed ${GREEN}$total_deleted${NC} installers, freed ${GREEN}${freed_mb}MB${NC}")
|
||||
summary_details+=("Your Mac is cleaner now!")
|
||||
fi
|
||||
else
|
||||
summary_details+=("No installers were removed")
|
||||
fi
|
||||
@@ -675,6 +684,9 @@ main() {
|
||||
"--debug")
|
||||
export MO_DEBUG=1
|
||||
;;
|
||||
"--dry-run" | "-n")
|
||||
export MOLE_DRY_RUN=1
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $arg"
|
||||
exit 1
|
||||
@@ -682,6 +694,11 @@ main() {
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "${MOLE_DRY_RUN:-0}" == "1" ]]; then
|
||||
echo -e "${YELLOW}${ICON_DRY_RUN} DRY RUN MODE${NC}, No installer files will be removed"
|
||||
printf '\n'
|
||||
fi
|
||||
|
||||
hide_cursor
|
||||
perform_installers
|
||||
local exit_code=$?
|
||||
|
||||
15
bin/purge.sh
15
bin/purge.sh
@@ -205,11 +205,18 @@ perform_purge() {
|
||||
rm -f "$stats_dir/purge_count"
|
||||
fi
|
||||
|
||||
if [[ "${MOLE_DRY_RUN:-0}" == "1" ]]; then
|
||||
summary_heading="Dry run complete - no changes made"
|
||||
fi
|
||||
|
||||
if [[ $total_size_cleaned -gt 0 ]]; then
|
||||
local freed_gb
|
||||
freed_gb=$(echo "$total_size_cleaned" | awk '{printf "%.2f", $1/1024/1024}')
|
||||
|
||||
local summary_line="Space freed: ${GREEN}${freed_gb}GB${NC}"
|
||||
if [[ "${MOLE_DRY_RUN:-0}" == "1" ]]; then
|
||||
summary_line="Would free: ${GREEN}${freed_gb}GB${NC}"
|
||||
fi
|
||||
[[ $total_items_cleaned -gt 0 ]] && summary_line+=" | Items: $total_items_cleaned"
|
||||
summary_line+=" | Free: $(get_free_space)"
|
||||
summary_details+=("$summary_line")
|
||||
@@ -233,6 +240,7 @@ show_help() {
|
||||
echo ""
|
||||
echo -e "${YELLOW}Options:${NC}"
|
||||
echo " --paths Edit custom scan directories"
|
||||
echo " --dry-run Preview purge actions without making changes"
|
||||
echo " --debug Enable debug logging"
|
||||
echo " --help Show this help message"
|
||||
echo ""
|
||||
@@ -262,6 +270,9 @@ main() {
|
||||
"--debug")
|
||||
export MO_DEBUG=1
|
||||
;;
|
||||
"--dry-run" | "-n")
|
||||
export MOLE_DRY_RUN=1
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $arg"
|
||||
echo "Use 'mo purge --help' for usage information"
|
||||
@@ -271,6 +282,10 @@ main() {
|
||||
done
|
||||
|
||||
start_purge
|
||||
if [[ "${MOLE_DRY_RUN:-0}" == "1" ]]; then
|
||||
echo -e "${YELLOW}${ICON_DRY_RUN} DRY RUN MODE${NC}, No project artifacts will be removed"
|
||||
printf '\n'
|
||||
fi
|
||||
hide_cursor
|
||||
perform_purge
|
||||
show_cursor
|
||||
|
||||
@@ -60,6 +60,10 @@ supports_touchid() {
|
||||
return 1
|
||||
}
|
||||
|
||||
touchid_dry_run_enabled() {
|
||||
[[ "${MOLE_DRY_RUN:-0}" == "1" ]]
|
||||
}
|
||||
|
||||
# Show current Touch ID status
|
||||
show_status() {
|
||||
if is_touchid_configured; then
|
||||
@@ -74,6 +78,16 @@ enable_touchid() {
|
||||
# Cleanup trap handled by global EXIT trap
|
||||
local temp_file=""
|
||||
|
||||
if touchid_dry_run_enabled; then
|
||||
if is_touchid_configured; then
|
||||
echo -e "${GREEN}${ICON_SUCCESS} Touch ID is already enabled, no changes needed${NC}"
|
||||
else
|
||||
echo -e "${GREEN}${ICON_SUCCESS} [DRY RUN] Would enable Touch ID for sudo${NC}"
|
||||
echo -e "${GRAY}${ICON_REVIEW} Target files: ${PAM_SUDO_FILE} and/or ${PAM_SUDO_LOCAL_FILE}${NC}"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
# First check if system supports Touch ID
|
||||
if ! supports_touchid; then
|
||||
log_warning "This Mac may not support Touch ID"
|
||||
@@ -201,6 +215,16 @@ disable_touchid() {
|
||||
# Cleanup trap handled by global EXIT trap
|
||||
local temp_file=""
|
||||
|
||||
if touchid_dry_run_enabled; then
|
||||
if ! is_touchid_configured; then
|
||||
echo -e "${YELLOW}Touch ID is not currently enabled${NC}"
|
||||
else
|
||||
echo -e "${GREEN}${ICON_SUCCESS} [DRY RUN] Would disable Touch ID for sudo${NC}"
|
||||
echo -e "${GRAY}${ICON_REVIEW} Target files: ${PAM_SUDO_FILE} and/or ${PAM_SUDO_LOCAL_FILE}${NC}"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! is_touchid_configured; then
|
||||
echo -e "${YELLOW}Touch ID is not currently enabled${NC}"
|
||||
return 0
|
||||
@@ -303,12 +327,39 @@ show_menu() {
|
||||
|
||||
# Main
|
||||
main() {
|
||||
local command="${1:-}"
|
||||
local command=""
|
||||
local arg
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
"--dry-run" | "-n")
|
||||
export MOLE_DRY_RUN=1
|
||||
;;
|
||||
"--help" | "-h")
|
||||
show_touchid_help
|
||||
return 0
|
||||
;;
|
||||
enable | disable | status)
|
||||
if [[ -z "$command" ]]; then
|
||||
command="$arg"
|
||||
else
|
||||
log_error "Only one touchid command is supported per run"
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown command: $arg"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if touchid_dry_run_enabled; then
|
||||
echo -e "${YELLOW}${ICON_DRY_RUN} DRY RUN MODE${NC}, No sudo authentication files will be modified"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
case "$command" in
|
||||
"--help" | "-h")
|
||||
show_touchid_help
|
||||
;;
|
||||
enable)
|
||||
enable_touchid
|
||||
;;
|
||||
|
||||
@@ -822,10 +822,17 @@ main() {
|
||||
"--debug")
|
||||
export MO_DEBUG=1
|
||||
;;
|
||||
"--dry-run" | "-n")
|
||||
export MOLE_DRY_RUN=1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
hide_cursor
|
||||
if [[ "${MOLE_DRY_RUN:-0}" == "1" ]]; then
|
||||
echo -e "${YELLOW}${ICON_DRY_RUN} DRY RUN MODE${NC}, No app files or settings will be modified"
|
||||
printf '\n'
|
||||
fi
|
||||
|
||||
local first_scan=true
|
||||
while true; do
|
||||
|
||||
Reference in New Issue
Block a user