Skip to content

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 unit rescans. Usual cost: one file read.
  • Duplicates are refused, not guessed. Two folders claiming one name (a copy, a backup) and unit names 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:

unit where nightly-backup
unit run nightly-backup --full     # cd there, exec backup.sh --full
unit ls

Limits

  • The search goes 6 levels deep and skips .git, node_modules, virtualenvs and build folders. Deeper units need another root in UNIT_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= or unit refuses both.

Code

methods/unit/ in the methods repository: the script, a README and a test.