repomatic.file_ops module

How this package puts a file on disk, and takes one off.

The counterpart of repomatic.file_inventory, which answers what is on disk: this one decides how something lands there. Format-neutral by design, and the reason it is its own module rather than a helper beside one format’s readers, where the CSV writer, the SVG chart renderer, the download cache and the release freeze each had to reach across for one.

Three concerns, deliberately separate, because a caller needs to pick:

  • write_if_changed() leaves a matching file untouched. Every generator leans on it rather than treating it as a nicety: one that rewrote its output unconditionally would turn each scheduled run into a commit, and a sync job opening a pull request would open one forever.

  • atomic_write() makes a half-written file unobservable. What a cache another process reads needs, and what a killed run must not leave behind.

  • unlink_with_empty_parents() removes a file or a whole component and takes the directories it emptied with it.

repomatic.file_ops.write_if_changed(path, content, previous=None)[source]

Write content to path, leaving an already-matching file alone.

Creates the parent directories when missing.

Parameters:
  • path (Path) – File to write.

  • content (str) – The full text the file should hold.

  • previous (str | None) – What the file holds already, when the caller has read it anyway. Left unset, the file is read back here to compare. A caller that transformed text it already had in hand passes it and skips the read.

Return type:

bool

Returns:

True when the file was created or its content changed.

repomatic.file_ops.atomic_write(dest, prefix, write)[source]

Write dest atomically: temp file in the target directory, then rename.

The other half of the question write_if_changed() answers. That one asks whether the bytes differ; this one asks whether a reader can ever observe half of them. A cache another process reads, or a file a killed run leaves behind, needs this one.

The rename is atomic on POSIX (same-filesystem rename) and safe on Windows (Path.replace overwrites atomically). write receives the temp path and fills it (its return value is ignored, so write_text/write_bytes pass straight through); partial writes are cleaned up on any failure.

Parameters:
  • dest (Path) – Final path the temp file is renamed onto.

  • prefix (str) – Prefix for the temp file, so a stray one names its owner.

  • write (Callable[[Path], object]) – Fills the temp path it is handed.

Return type:

None

Delete target, then prune now-empty parent directories up to root.

target may be a directory, removed with everything it carries: what is being deleted is often a whole component rather than one file.

Stops at the first parent that still holds something, and never touches root itself.

Parameters:
  • target (Path) – File or directory to delete.

  • root (Path) – Directory the upward pruning stops below.

Return type:

None