diff --git a/README.md b/README.md index e76e89a..36d7938 100644 --- a/README.md +++ b/README.md @@ -202,6 +202,23 @@ Select Categories to Clean - 18.5GB (8 selected) > **Use with caution:** This will permanently delete selected artifacts. Review carefully before confirming. Recent projects (< 7 days) are marked and unselected by default. +#### Configuration + +You can configure which directories `mole` scans for projects by creating a config file: + +1. Create `~/.config/mole/purge_paths` +2. Add one directory path per line (supports `~`) + +Example `~/.config/mole/purge_paths`: + +``` +~/Documents/MyProjects +~/Work/ClientA +~/Work/ClientB +``` + +If this file exists, `mole` will *only* scan the paths listed in it. If not, it uses the default paths (`~/Projects`, `~/GitHub`, `~/dev`, etc.). + ## Quick Launchers Launch Mole commands instantly from Raycast or Alfred: diff --git a/bin/purge.sh b/bin/purge.sh index 46ecac1..b4bb884 100755 --- a/bin/purge.sh +++ b/bin/purge.sh @@ -111,6 +111,26 @@ perform_purge() { printf '\n' } +# Show help message +show_help() { + echo -e "${PURPLE_BOLD}Mole Purge${NC} - Clean old project build artifacts" + echo "" + echo -e "${YELLOW}Usage:${NC} mo purge [options]" + echo "" + echo -e "${YELLOW}Options:${NC}" + echo " --help Show this help message" + echo " --debug Enable debug logging" + echo "" + echo -e "${YELLOW}Configuration:${NC}" + echo " To customize search paths, create: ${NC}$HOME/.config/mole/purge_paths${NC}" + echo " Add one directory path per line (supports ~)." + echo "" + echo -e "${YELLOW}Default Paths:${NC}" + for path in "${DEFAULT_PURGE_SEARCH_PATHS[@]}"; do + echo " - $path" + done +} + # Main entry point main() { # Set up signal handling @@ -119,12 +139,16 @@ main() { # Parse arguments for arg in "$@"; do case "$arg" in + "--help") + show_help + exit 0 + ;; "--debug") export MO_DEBUG=1 ;; *) echo "Unknown option: $arg" - echo "Use 'mo --help' for usage information" + echo "Use 'mo purge --help' for usage information" exit 1 ;; esac diff --git a/lib/clean/project.sh b/lib/clean/project.sh index 115e76d..8def3b9 100644 --- a/lib/clean/project.sh +++ b/lib/clean/project.sh @@ -27,7 +27,8 @@ readonly MIN_AGE_DAYS=7 readonly PURGE_MIN_DEPTH_DEFAULT=2 readonly PURGE_MAX_DEPTH_DEFAULT=8 # Search paths (only project directories) -readonly PURGE_SEARCH_PATHS=( +# Search paths (default) +readonly DEFAULT_PURGE_SEARCH_PATHS=( "$HOME/www" "$HOME/dev" "$HOME/Projects" @@ -37,6 +38,40 @@ readonly PURGE_SEARCH_PATHS=( "$HOME/Repos" "$HOME/Development" ) + +# Config file for custom purge paths +readonly PURGE_CONFIG_FILE="$HOME/.config/mole/purge_paths" + +# Global array to hold actual search paths +PURGE_SEARCH_PATHS=() + +# Load purge paths from config or defaults +load_purge_config() { + PURGE_SEARCH_PATHS=() + if [[ -f "$PURGE_CONFIG_FILE" ]]; then + while IFS= read -r line; do + # Remove leading/trailing whitespace + line="${line#"${line%%[![:space:]]*}"}" + line="${line%"${line##*[![:space:]]}"}" + + # Skip empty lines and comments + [[ -z "$line" || "$line" =~ ^# ]] && continue + + # Expand tilde to HOME + line="${line/#\~/$HOME}" + + PURGE_SEARCH_PATHS+=("$line") + done < "$PURGE_CONFIG_FILE" + fi + + # Fallback to defaults if no paths loaded + if [[ ${#PURGE_SEARCH_PATHS[@]} -eq 0 ]]; then + PURGE_SEARCH_PATHS=("${DEFAULT_PURGE_SEARCH_PATHS[@]}") + fi +} + +# Initialize paths +load_purge_config # Args: $1 - path to check # Check if path is safe to clean (must be inside a project directory) is_safe_project_artifact() { diff --git a/tests/purge_config.bats b/tests/purge_config.bats new file mode 100644 index 0000000..dfafb4f --- /dev/null +++ b/tests/purge_config.bats @@ -0,0 +1,124 @@ +#!/usr/bin/env bats + +setup_file() { + PROJECT_ROOT="$(cd "${BATS_TEST_DIRNAME}/.." && pwd)" + export PROJECT_ROOT + + ORIGINAL_HOME="${HOME:-}" + export ORIGINAL_HOME + + HOME="$(mktemp -d "${BATS_TEST_DIRNAME}/tmp-purge-config.XXXXXX")" + export HOME + + mkdir -p "$HOME" +} + +teardown_file() { + rm -rf "$HOME" + if [[ -n "${ORIGINAL_HOME:-}" ]]; then + export HOME="$ORIGINAL_HOME" + fi +} + +setup() { + rm -rf "$HOME/.config" + mkdir -p "$HOME/.config/mole" +} + +@test "load_purge_config loads default paths when config file is missing" { + # Source the file in a subshell to avoid polluting test environment variables + # We need to export HOME so it's picked up by the script + run env HOME="$HOME" bash -c "source '$PROJECT_ROOT/lib/clean/project.sh'; echo \"\${PURGE_SEARCH_PATHS[*]}\"" + + [ "$status" -eq 0 ] + + # Check for a few expected default paths + [[ "$output" == *"$HOME/Projects"* ]] + [[ "$output" == *"$HOME/GitHub"* ]] + [[ "$output" == *"$HOME/dev"* ]] +} + +@test "load_purge_config loads custom paths from config file" { + local config_file="$HOME/.config/mole/purge_paths" + + cat > "$config_file" << EOF +$HOME/custom/projects +$HOME/work +EOF + + run env HOME="$HOME" bash -c "source '$PROJECT_ROOT/lib/clean/project.sh'; echo \"\${PURGE_SEARCH_PATHS[*]}\"" + + [ "$status" -eq 0 ] + + [[ "$output" == *"$HOME/custom/projects"* ]] + [[ "$output" == *"$HOME/work"* ]] + # Should NOT have default paths + [[ "$output" != *"$HOME/GitHub"* ]] +} + +@test "load_purge_config expands tilde in paths" { + local config_file="$HOME/.config/mole/purge_paths" + + cat > "$config_file" << EOF +~/tilde/expanded +~/another/one +EOF + + run env HOME="$HOME" bash -c "source '$PROJECT_ROOT/lib/clean/project.sh'; echo \"\${PURGE_SEARCH_PATHS[*]}\"" + + [ "$status" -eq 0 ] + + [[ "$output" == *"$HOME/tilde/expanded"* ]] + [[ "$output" == *"$HOME/another/one"* ]] + [[ "$output" != *"~"* ]] +} + +@test "load_purge_config ignores comments and empty lines" { + local config_file="$HOME/.config/mole/purge_paths" + + cat > "$config_file" << EOF +# This is a comment +$HOME/valid/path + + # Indented comment + +$HOME/another/path +EOF + + run env HOME="$HOME" bash -c "source '$PROJECT_ROOT/lib/clean/project.sh'; echo \"\${#PURGE_SEARCH_PATHS[@]}\"; echo \"\${PURGE_SEARCH_PATHS[*]}\"" + + [ "$status" -eq 0 ] + + local lines + read -r -a lines <<< "$output" + # First line of output is count + local count="${lines[0]}" + + [ "$count" -eq 2 ] + [[ "$output" == *"$HOME/valid/path"* ]] + [[ "$output" == *"$HOME/another/path"* ]] +} + +@test "load_purge_config falls back to defaults if config file is empty" { + local config_file="$HOME/.config/mole/purge_paths" + touch "$config_file" + + run env HOME="$HOME" bash -c "source '$PROJECT_ROOT/lib/clean/project.sh'; echo \"\${PURGE_SEARCH_PATHS[*]}\"" + + [ "$status" -eq 0 ] + + # Should have default paths + [[ "$output" == *"$HOME/Projects"* ]] +} + +@test "load_purge_config falls back to defaults if config file has only comments" { + local config_file="$HOME/.config/mole/purge_paths" + echo "# Just a comment" > "$config_file" + + run env HOME="$HOME" bash -c "source '$PROJECT_ROOT/lib/clean/project.sh'; echo \"\${PURGE_SEARCH_PATHS[*]}\"" + + [ "$status" -eq 0 ] + + # Should have default paths + [[ "$output" == *"$HOME/Projects"* ]] +}