Skip to content

Commit 21ae4ed

Browse files
committed
feat: skip already-excluded directories for faster subsequent runs
Use Spotlight metadata (mdfind) to identify directories already excluded from Time Machine and skip them during the find traversal. Also fixes a comment typo and removes duplicate Gradle sentinel entries. Inspired by stevegrunwell#97, props @VladRassokhin.
1 parent 0fb96d3 commit 21ae4ed

File tree

5 files changed

+48
-4
lines changed

5 files changed

+48
-4
lines changed

CHANGELOG.md

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

3636
### Changed
3737

38+
* Skip directories already excluded from Time Machine backups for faster subsequent runs (inspired by [stevegrunwell/asimov#97], props @VladRassokhin)
3839
* Migrated test suite from PHP/PHPUnit to [Bats](https://github.com/bats-core/bats-core) (Bash Automated Testing System), removing the PHP dependency for contributors
3940
* Replaced Travis CI pipeline with GitHub Actions (macOS 14 + 15 matrix)
4041
* Replaced PHP `tmutil` mock with a pure bash implementation
4142
* Moved install script to `scripts/install.sh` with shared variables, now copies binary instead of symlinking ([#35], props @sylver)
4243

44+
### Fixed
45+
46+
* Fixed duplicate Gradle sentinel entries in the sentinels list
47+
* Fixed typo in comment ("decendents" → "descendants")
48+
4349
### Removed
4450

4551
* Removed PHP test infrastructure (`composer.json`, `phpunit.xml.dist`, and PHP test files)
@@ -122,3 +128,4 @@ Initial public release.
122128
[#56]: https://github.com/stevegrunwell/asimov/pull/56
123129
[stevegrunwell/asimov#64]: https://github.com/stevegrunwell/asimov/pull/64
124130
[stevegrunwell/asimov#87]: https://github.com/stevegrunwell/asimov/pull/87
131+
[stevegrunwell/asimov#97]: https://github.com/stevegrunwell/asimov/pull/97

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ test: ## Run Bats tests
99
@bats tests/sentinels.bats tests/behavior.bats
1010

1111
lint: ## Run Shellcheck on all shell scripts
12-
@shellcheck asimov scripts/install.sh scripts/uninstall.sh tests/bin/run-tests.sh tests/bin/tmutil
12+
@shellcheck asimov scripts/install.sh scripts/uninstall.sh tests/bin/run-tests.sh tests/bin/tmutil tests/bin/mdfind
1313

1414
check: test lint ## Run tests and linting
1515

asimov

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ set -Eeu -o pipefail
2020
readonly ASIMOV_ROOT=~
2121

2222
# Paths to unconditionally skip over. This prevents Asimov from modifying the
23-
# Time Machine exclusions for these paths (and decendents). It has an important
23+
# Time Machine exclusions for these paths (and descendants). It has an important
2424
# side-effect of speeding up the search.
2525
readonly ASIMOV_SKIP_PATHS=(
2626
~/.Trash
@@ -51,8 +51,6 @@ readonly ASIMOV_VENDOR_DIR_SENTINELS=(
5151
'Pods Podfile' # CocoaPods
5252
'DerivedData *.xcodeproj' # Xcode DerivedData
5353
'bower_components bower.json' # Bower (JavaScript)
54-
'build build.gradle' # Gradle
55-
'build build.gradle.kts' # Gradle Kotlin Script
5654
'build pubspec.yaml' # Flutter (Dart)
5755
'build setup.py' # Python
5856
'dist setup.py' # PyPI Publishing (Python)
@@ -121,6 +119,13 @@ for d in "${ASIMOV_SKIP_PATHS[@]}"; do
121119
find_parameters_skip+=( -not \( -path "${d}" -prune \) )
122120
done
123121

122+
# Skip directories already excluded from Time Machine backups.
123+
# Uses Spotlight metadata which may not report all exclusions — any missed
124+
# directories are still handled by the tmutil isexcluded check in exclude_file().
125+
while IFS= read -r line; do
126+
[[ -n "$line" ]] && find_parameters_skip+=( -not \( -path "${line}" -prune \) )
127+
done < <(mdfind -onlyin "${ASIMOV_ROOT}" "com_apple_backup_excludeItem = 'com.apple.backupd'" 2>/dev/null | sort -u)
128+
124129
# Iterate over the directory/sentinel pairs to construct the `find` expression.
125130
declare -a find_parameters_vendor=()
126131
for i in "${ASIMOV_VENDOR_DIR_SENTINELS[@]}"; do

tests/behavior.bats

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,27 @@ load test_helper
141141
refute_excluded "${HOME}/Code/My-Project/node_modules/dep/node_modules"
142142
[[ "$(count_exclusions)" -eq 1 ]]
143143
}
144+
145+
# =============================================================================
146+
# Skip already-excluded directories (mdfind optimization)
147+
# =============================================================================
148+
149+
@test "skips directories already excluded from Time Machine" {
150+
create_project "Code/Already-Excluded" "package.json" "node_modules"
151+
create_project "Code/New-Project" "package.json" "node_modules"
152+
153+
# Pre-exclude the first project manually
154+
echo "${HOME}/Code/Already-Excluded/node_modules" > "$ASIMOV_TEST_EXCLUSIONS"
155+
156+
# Tell mock mdfind to report it as already excluded
157+
ASIMOV_TEST_MDFIND_RESULTS="${TEST_TEMP_DIR}/.mdfind_results"
158+
export ASIMOV_TEST_MDFIND_RESULTS
159+
echo "${HOME}/Code/Already-Excluded" > "$ASIMOV_TEST_MDFIND_RESULTS"
160+
161+
run_asimov
162+
163+
# The new project should be excluded
164+
assert_excluded "${HOME}/Code/New-Project/node_modules"
165+
# The already-excluded one should still only have 1 entry (not duplicated)
166+
[[ "$(count_exclusions)" -eq 2 ]]
167+
}

tests/bin/mdfind

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env bash
2+
# Mock mdfind for testing — returns nothing by default.
3+
# Set ASIMOV_TEST_MDFIND_RESULTS to a file path to return its contents.
4+
set -euo pipefail
5+
6+
if [[ -n "${ASIMOV_TEST_MDFIND_RESULTS:-}" && -f "${ASIMOV_TEST_MDFIND_RESULTS}" ]]; then
7+
cat "${ASIMOV_TEST_MDFIND_RESULTS}"
8+
fi

0 commit comments

Comments
 (0)