diff --git a/lib/clean/project.sh b/lib/clean/project.sh index cea5504..9e5b013 100644 --- a/lib/clean/project.sh +++ b/lib/clean/project.sh @@ -220,6 +220,36 @@ is_safe_project_artifact() { fi return 0 } + +is_rails_project_root() { + local dir="$1" + [[ -f "$dir/config/application.rb" ]] || return 1 + [[ -f "$dir/Gemfile" ]] || return 1 + [[ -f "$dir/bin/rails" || -f "$dir/config/environment.rb" ]] +} + +is_rails_vendor_dir() { + local path="$1" + local base + base=$(basename "$path") + [[ "$base" == "vendor" ]] || return 1 + is_rails_project_root "$(dirname "$path")" +} + +is_protected_purge_artifact() { + local path="$1" + local base + base=$(basename "$path") + case "$base" in + vendor) + if is_rails_vendor_dir "$path"; then + return 0 + fi + ;; + esac + return 1 +} + # Scan purge targets using fd (fast) or pruned find. scan_purge_targets() { local search_path="$1" @@ -259,7 +289,7 @@ scan_purge_targets() { if is_safe_project_artifact "$item" "$search_path"; then echo "$item" fi - done | filter_nested_artifacts > "$output_file" + done | filter_nested_artifacts | filter_protected_artifacts > "$output_file" else # Pruned find avoids descending into heavy directories. local prune_args=() @@ -287,7 +317,7 @@ scan_purge_targets() { if is_safe_project_artifact "$item" "$search_path"; then echo "$item" fi - done | filter_nested_artifacts > "$output_file" + done | filter_nested_artifacts | filter_protected_artifacts > "$output_file" fi } # Filter out nested artifacts (e.g. node_modules inside node_modules). @@ -306,6 +336,14 @@ filter_nested_artifacts() { fi done } + +filter_protected_artifacts() { + while IFS= read -r item; do + if ! is_protected_purge_artifact "$item"; then + echo "$item" + fi + done +} # Args: $1 - path # Check if a path was modified recently (safety check). is_recently_modified() { diff --git a/tests/purge.bats b/tests/purge.bats index 805188b..b092148 100644 --- a/tests/purge.bats +++ b/tests/purge.bats @@ -101,6 +101,54 @@ setup() { [[ "$result" == "2" ]] } +@test "scan_purge_targets: skips Rails vendor directory" { + mkdir -p "$HOME/www/rails-app/vendor/javascript" + mkdir -p "$HOME/www/rails-app/config" + touch "$HOME/www/rails-app/config/application.rb" + touch "$HOME/www/rails-app/Gemfile" + mkdir -p "$HOME/www/rails-app/bin" + touch "$HOME/www/rails-app/bin/rails" + + local scan_output + scan_output="$(mktemp)" + + result=$(bash -c " + source '$PROJECT_ROOT/lib/clean/project.sh' + scan_purge_targets '$HOME/www' '$scan_output' + if grep -q '$HOME/www/rails-app/vendor' '$scan_output'; then + echo 'FOUND' + else + echo 'SKIPPED' + fi + ") + + rm -f "$scan_output" + + [[ "$result" == "SKIPPED" ]] +} + +@test "scan_purge_targets: keeps non-Rails vendor directory" { + mkdir -p "$HOME/www/php-app/vendor" + touch "$HOME/www/php-app/composer.json" + + local scan_output + scan_output="$(mktemp)" + + result=$(bash -c " + source '$PROJECT_ROOT/lib/clean/project.sh' + scan_purge_targets '$HOME/www' '$scan_output' + if grep -q '$HOME/www/php-app/vendor' '$scan_output'; then + echo 'FOUND' + else + echo 'MISSING' + fi + ") + + rm -f "$scan_output" + + [[ "$result" == "FOUND" ]] +} + @test "is_recently_modified: detects recent projects" { mkdir -p "$HOME/www/project/node_modules" touch "$HOME/www/project/package.json"