Skip to content

Commit a35abbe

Browse files
authored
Merge pull request #123 from AsimovMac/fix/cache-permissions-and-doctor
fix(cache): survive an unusable cache, and add asimov doctor
2 parents 4cb85a4 + 5fa686d commit a35abbe

10 files changed

Lines changed: 1111 additions & 26 deletions

File tree

CHANGELOG.md

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

99
### Added
1010

11+
- `asimov doctor` checks an install rather than your projects: which `asimov` your shell
12+
actually runs (and flags an older one shadowing it on `PATH`), whether a schedule is
13+
installed and loaded, whether `~/.cache/asimov/` is readable and writable by you,
14+
whether the config file parses, and whether `tmutil` can read exclusions at all. It is
15+
read-only — it prints the fix rather than applying it — and never executes another
16+
`asimov` binary it finds, reading versions out of the file instead, because v0.3.0
17+
ignores every argument and would start a real scan. Exits `1` if it finds anything
18+
([#122](https://github.com/AsimovMac/asimov/issues/122)).
19+
- `UPGRADING.md`: a section for upgrading from v0.3.0, the version most people have,
20+
covering the three leftovers that outlive it — the LaunchAgent, the old cellar, and a
21+
root-owned cache — in an order that works
22+
([#122](https://github.com/AsimovMac/asimov/issues/122)).
23+
1124
- `make test-system-bash` runs the suite under the macOS system bash (3.2), which is what
1225
most users get — `asimov` starts with `#!/usr/bin/env bash`, and a development machine
1326
usually has 5.x first on `PATH`. `make test BASH_BIN=<path>` pins any interpreter, and
@@ -35,6 +48,18 @@ This project adheres to [Semantic Versioning](http://semver.org/).
3548

3649
### Fixed
3750

51+
- An unreadable or unwritable file under `~/.cache/asimov/` no longer kills the run. The
52+
cache is an optimisation, but a bare `cat` on an unreadable state file failed under
53+
`set -Eeu -o pipefail` and aborted immediately, printing nothing but `Permission
54+
denied`. Every cache read and write is now guarded: Asimov warns once, names the reset
55+
command, and continues without the cache
56+
([#122](https://github.com/AsimovMac/asimov/issues/122)).
57+
- A run as root no longer leaves root-owned files behind that break the next run as your
58+
own user — the cause of the failure above. The cache directory was chowned to the
59+
console user, but the state files written afterwards were not; they are now created
60+
before the chown, and appending never changes an existing file's owner
61+
([#122](https://github.com/AsimovMac/asimov/issues/122)).
62+
3863
### Removed
3964

4065
## [0.10.0] — 2026-07-26

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ If `mdfind` doesn't list your projects, the run isn't reaching them. The two usu
132132

133133
```
134134
asimov [--dry-run] [--verbose] [--quiet] [--stats] [--no-read-cache] [--no-write-cache] [--help] [--version]
135+
asimov prune [--quiet]
136+
asimov doctor [--quiet]
135137
```
136138

137139

@@ -180,6 +182,44 @@ Asimov keeps a cache under `~/.cache/asimov/` so repeat runs are near-instant. T
180182
- Both together = a fully stateless run that reads and writes nothing. **`--no-cache` is an alias for this.**
181183

182184

185+
### `asimov doctor`
186+
187+
Checks the install itself rather than your projects. Run it when something seems off, or straight after an upgrade.
188+
189+
```
190+
$ asimov doctor
191+
192+
Asimov doctor
193+
194+
Install
195+
✓ asimov 0.10.0 (/opt/homebrew/bin/asimov)
196+
✗ typing 'asimov' runs a different binary — this one is shadowed
197+
/usr/local/bin/asimov (version 0.3.0)
198+
Remove the one you don't want, or fix the order of PATH.
199+
200+
Schedule
201+
✗ homebrew.mxcl.asimov: its program /opt/homebrew/Cellar/asimov/0.3.0/bin/asimov no longer exists
202+
launchctl bootout gui/$(id -u)/homebrew.mxcl.asimov
203+
rm ~/Library/LaunchAgents/homebrew.mxcl.asimov.plist
204+
205+
Cache
206+
✗ ~/.cache/asimov/excluded is not readable and writable by you (owner: root)
207+
A run as root left these behind. Clear them:
208+
rm -rf ~/.cache/asimov
209+
210+
Config
211+
✓ ~/.config/asimov/config looks valid
212+
213+
Time Machine
214+
✓ tmutil can read exclusions
215+
216+
3 problems found.
217+
```
218+
219+
It covers five things: which `asimov` your shell actually runs, whether a schedule is installed and loaded, whether the cache is readable and writable by you, whether the config parses, and whether `tmutil` can read exclusions at all (it can't without Full Disk Access).
220+
221+
`doctor` is **read-only** — it prints the fix rather than applying it — and it never executes another `asimov` binary it finds, reading versions out of the file instead. It exits `1` if it finds anything, so it's safe to use in a script.
222+
183223
## Schedule
184224

185225
The curl and source installers set up a daily launchd job automatically. To trigger one immediately or stop the schedule:

UPGRADING.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,71 @@
11
# Upgrading Asimov
22

3+
## To v0.10.0 from v0.3.0 (the original `stevegrunwell/asimov`)
4+
5+
Most people upgrading are coming from `0.3.0`, the version Homebrew shipped for years.
6+
It upgrades cleanly, but three leftovers can outlive it. Work through this in order.
7+
8+
**Before you start: don't run `asimov` to check your version.** v0.3.0 parses no
9+
arguments at all — it ignores `--version`, `--help`, and every subcommand, and goes
10+
straight to scanning and writing Time Machine exclusions. Read the version out of the
11+
file instead:
12+
13+
```sh
14+
grep -m1 -E '@version|ASIMOV_VERSION=' "$(command -v asimov)"
15+
```
16+
17+
### 1. Stop the schedule before you uninstall
18+
19+
Uninstalling first leaves the LaunchAgent behind with nothing to run:
20+
21+
```sh
22+
brew services stop asimov
23+
launchctl bootout gui/$(id -u)/homebrew.mxcl.asimov 2>/dev/null
24+
rm -f ~/Library/LaunchAgents/homebrew.mxcl.asimov.plist
25+
```
26+
27+
### 2. Replace the binary
28+
29+
```sh
30+
brew uninstall asimov
31+
brew install asimov
32+
```
33+
34+
If `brew uninstall` reports `Permission denied @ apply2files`, the old cellar files are
35+
owned by another user — Homebrew prints the `sudo` command to force it, and that is safe
36+
here.
37+
38+
### 3. Clear the old cache
39+
40+
v0.10.0 keeps state in `~/.cache/asimov/`. If anything ever ran Asimov as root, those
41+
files are root-owned and unreadable by you:
42+
43+
```sh
44+
rm -rf ~/.cache/asimov
45+
```
46+
47+
v0.10.0 and earlier crashed outright on this with a bare `Permission denied`. Current
48+
versions warn and carry on, but clearing it is still the fix.
49+
50+
### 4. Check the result
51+
52+
`doctor` exists only in current versions, so it comes last — there is nothing to run
53+
before the new binary is in place:
54+
55+
```sh
56+
asimov doctor
57+
```
58+
59+
It reports a shadowed binary, a leftover schedule, an unreadable cache, and a bad config,
60+
and exits non-zero if it finds any. If it prints usage errors or starts a scan instead,
61+
an old binary is still first on your `PATH``doctor` names the one it found.
62+
63+
### One thing that isn't broken
64+
65+
Asimov is a one-shot scan, not a daemon. After `brew services start asimov`, `ps aux |
66+
grep asimov` finding nothing is expected: it scans, excludes, and exits. To confirm it is
67+
actually scheduled, use `asimov doctor`.
68+
369
## To v0.10.0 (from the `django23/asimov` fork)
470

571
`0.10.0` folds the fork's work (v0.4.0–v0.8.0, plus a `v0.9.0-beta` round) back into

0 commit comments

Comments
 (0)