Skip to content

Commit feb64a1

Browse files
committed
feat: exclude well-known global cache directories
Add fixed directory exclusions for common tool caches (~/.cache, ~/.gradle/caches, ~/.m2/repository, ~/.npm/_cacache, ~/.nuget/packages, ~/.kube/cache) that are always safe to exclude without sentinel files. Inspired by stevegrunwell#69, props @pkuczynski.
1 parent 64834be commit feb64a1

File tree

4 files changed

+70
-1
lines changed

4 files changed

+70
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
88

99
### Added
1010

11+
* Exclude well-known global cache directories (`~/.cache`, `~/.gradle/caches`, `~/.m2/repository`, `~/.npm/_cacache`, `~/.nuget/packages`, `~/.kube/cache`, etc.) without requiring sentinel files (inspired by [stevegrunwell/asimov#69], props @pkuczynski)
1112
* Exclude Next.js build cache (`.next`)
1213
* Exclude Nuxt build cache (`.nuxt`)
1314
* Exclude Angular CLI cache (`.angular`)
@@ -117,3 +118,4 @@ Initial public release.
117118
[#55]: https://github.com/stevegrunwell/asimov/pull/55
118119
[#35]: https://github.com/stevegrunwell/asimov/pull/35
119120
[#56]: https://github.com/stevegrunwell/asimov/pull/56
121+
[stevegrunwell/asimov#69]: https://github.com/stevegrunwell/asimov/pull/69

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Asimov recognizes dependency directories across **30+ patterns** in these ecosys
4848
| **R** | `renv` |
4949
| **DevOps / IaC** | `.terraform`, `.terragrunt-cache`, `.vagrant`, `.direnv`, `cdk.out` |
5050
| **Game dev** | `.godot` |
51+
| **Global caches** | `~/.cache`, `~/.gradle/caches`, `~/.m2/repository`, `~/.npm/_cacache`, `~/.nuget/packages`, `~/.kube/cache` |
5152

5253
Each directory is only excluded when its corresponding config file (the "sentinel") exists — so `node_modules` is only excluded if `package.json` is present, `vendor` only if `composer.json`, `go.mod`, or `Gemfile` exists, etc.
5354

@@ -93,7 +94,7 @@ brew uninstall asimov
9394

9495
## How it works
9596

96-
Asimov is a thin wrapper around Apple's [`tmutil`](https://ss64.com/mac/tmutil.html). It builds a single `find` command from all known dependency patterns, walks your home directory (skipping `~/Library` and `~/.Trash`), and pipes matching paths through `tmutil addexclusion`. Directories already excluded are skipped automatically — safe to run as often as you like.
97+
Asimov is a thin wrapper around Apple's [`tmutil`](https://ss64.com/mac/tmutil.html). It builds a single `find` command from all known dependency patterns, walks your home directory (skipping `~/Library` and `~/.Trash`), and pipes matching paths through `tmutil addexclusion`. It also unconditionally excludes well-known global tool caches (like `~/.cache`, `~/.gradle/caches`, and `~/.npm/_cacache`) that can always be safely restored. Directories already excluded are skipped automatically — safe to run as often as you like.
9798

9899
### Inspecting exclusions
99100

asimov

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,22 @@ readonly ASIMOV_VENDOR_DIR_SENTINELS=(
9393
'renv renv.lock' # renv (R)
9494
)
9595

96+
# A list of fixed directories to exclude from Time Machine backups.
97+
#
98+
# Unlike sentinel-based pairs above, these directories are always excluded
99+
# when they exist — they represent global tool caches and artifacts that
100+
# can be safely restored.
101+
readonly ASIMOV_FIXED_DIRS=(
102+
~/.cache # XDG cache directory
103+
~/.gradle/caches # Gradle download cache
104+
~/.gradle/wrapper # Gradle wrapper distributions
105+
~/.m2/repository # Maven local repository
106+
~/.npm/_cacache # npm content-addressable cache
107+
~/.nuget/packages # NuGet global packages
108+
~/.kube/cache # Kubernetes API cache
109+
~/.kube/http-cache # Kubernetes HTTP cache
110+
)
111+
96112
# Exclude the given paths from Time Machine backups.
97113
# Reads the newline-separated list of paths from stdin.
98114
exclude_file() {
@@ -144,3 +160,11 @@ printf '\n\033[0;36mFinding dependency directories with corresponding definition
144160
find "${ASIMOV_ROOT}" \( "${find_parameters_skip[@]}" \) \( -false "${find_parameters_vendor[@]}" \) \
145161
| exclude_file \
146162
;
163+
164+
# Exclude fixed directories (global tool caches) when they exist.
165+
printf '\n\033[0;36mExcluding known cache directories…\033[0m\n'
166+
for dir in "${ASIMOV_FIXED_DIRS[@]}"; do
167+
if [[ -d "$dir" ]]; then
168+
echo "$dir"
169+
fi
170+
done | exclude_file

tests/behavior.bats

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,45 @@ load test_helper
127127
refute_excluded "${HOME}/Code/My-Project/node_modules/dep/node_modules"
128128
[[ "$(count_exclusions)" -eq 1 ]]
129129
}
130+
131+
# =============================================================================
132+
# Fixed directories (global caches)
133+
# =============================================================================
134+
135+
@test "excludes fixed directory when it exists" {
136+
mkdir -p "${HOME}/.cache"
137+
run_asimov
138+
assert_excluded "${HOME}/.cache"
139+
}
140+
141+
@test "does not fail when fixed directory does not exist" {
142+
# Don't create any fixed dirs — asimov should still succeed
143+
run_asimov
144+
[[ "$status" -eq 0 ]]
145+
[[ "$(count_exclusions)" -eq 0 ]]
146+
}
147+
148+
@test "excludes multiple fixed directories when they exist" {
149+
mkdir -p "${HOME}/.cache"
150+
mkdir -p "${HOME}/.gradle/caches"
151+
mkdir -p "${HOME}/.npm/_cacache"
152+
run_asimov
153+
assert_excluded "${HOME}/.cache"
154+
assert_excluded "${HOME}/.gradle/caches"
155+
assert_excluded "${HOME}/.npm/_cacache"
156+
[[ "$(count_exclusions)" -eq 3 ]]
157+
}
158+
159+
@test "does not re-exclude already excluded fixed directory" {
160+
mkdir -p "${HOME}/.cache"
161+
run_asimov
162+
assert_excluded "${HOME}/.cache"
163+
local first_count
164+
first_count="$(count_exclusions)"
165+
[[ "$first_count" -eq 1 ]]
166+
167+
run_asimov
168+
local second_count
169+
second_count="$(count_exclusions)"
170+
[[ "$second_count" -eq 1 ]]
171+
}

0 commit comments

Comments
 (0)