unit: find a folder by its marker, not its path¶
The problem¶
Scheduled jobs, shell aliases, symlinks and notes all hold written-out paths. Reorganise your folders once and every one of them points at nothing. The job fails at 3am, the alias errors, the note sends its reader to a dead end.
The method¶
Turn it around: the folder says who it is, and callers ask by name. A folder becomes a unit by holding one small file:
.unit
name=nightly-backup
run=backup.sh
A scheduler runs unit run nightly-backup; a script uses
cd "$(unit where nightly-backup)". Move or rename the folder anywhere under
the search roots and the next call finds it.
Three details keep it fast and honest:
- A cache of symlinks, checked before it is trusted. The cache link is
followed only if the marker is still there and still carries that name;
otherwise
unitrescans. Usual cost: one file read. - Duplicates are refused, not guessed. Two folders claiming one name (a
copy, a backup) and
unitnames both and stops. Running the wrong copy is worse than not running. - Atomic links. Each cache link is made under a temp name and renamed into place, so jobs starting together never see a half-made link.
Sample¶
The lookup, in Python:
def locate(name):
link = CACHE / name
marker = link / ".unit"
if marker.is_file() and (parse(marker).get("name") or link.resolve().name) == name:
return link.resolve() # cache still true: one file read
units = scan() # walk the roots for .unit files
remember(units) # rewrite the symlink cache
if name not in units:
sys.exit(f"unit: no folder marked '{name}'")
return units[name]
Use it:
Limits¶
- The search goes 6 levels deep and skips
.git,node_modules, virtualenvs and build folders. Deeper units need another root inUNIT_ROOTS. - The first lookup after a move walks the roots; on a large home folder that takes seconds.
- A copied folder carries its marker. Rename the copy's
name=orunitrefuses both.
Code¶
methods/unit/ in the methods repository: the script, a README and a test.