Atomic writes & idempotency¶
Shotty treats the target PNG file like a build artefact that other tools (file watchers, dev servers, Git, CI) might be observing. Three guarantees flow from that.
1. Atomic writes — no half-written PNGs¶
Renders are written to a hidden temp file in the same directory as
the target (.foo.png.shotty.<pid>.tmp), then rename(2)d into
place once the encoder finalizes. If the render or encode fails, the
temp file is unlinked; the existing target stays intact and untouched.
A reader holding the target PNG always sees a complete, valid file — never a partially-written one. The temp lives in the same directory so the rename is atomic on POSIX filesystems (cross-device renames aren't atomic).
2. Refuse to overwrite anything that isn't already a PNG¶
Before doing any work, Shotty checks the target path:
- If it doesn't exist → proceed.
- If it's a directory → abort with a clear error.
- If it's a regular file but the first 8 bytes aren't the PNG magic
number (
89 50 4E 47 0D 0A 1A 0A) → abort.
So pointing -o at, say, your ~/.zshrc won't silently destroy it.
You'd have to delete the file manually first.
3. Skip the rename if pixels are identical¶
After rendering into memory but before the rename, Shotty checks
whether the target file already exists. If it does, the existing PNG
is decoded back into 8-bit RGBA and compared to the new render with
memcmp. If the bytes match, the rename doesn't happen:
- The temp file is removed.
- The target's
mtimestays unchanged. - Shotty prints
💤 path/to.png unchanged (...).
This is what makes shotty --render-all
genuinely idempotent: re-running it is a no-op when nothing has
changed. File watchers stay quiet, Git's working tree stays clean,
ReadTheDocs and similar build systems don't see spurious changes,
and CI can use git diff --exit-code as a "docs are out of date"
gate.
The comparison happens in pixel space, not file-bytes space, because two PNG encoders (or two runs of the same encoder with different zlib settings) can produce different file bytes for the same image. Decoding both sides into a normalized RGBA buffer is the only reliable way to say "these two PNGs would look identical."
See also¶
- For OSS maintainers — the bulk-render workflow that depends on this
-oflag — output path