repomatic.cache module

Global cache for downloaded tool executables, HTTP API responses, and generated tool configurations.

Three cache subtrees under the user-level cache directory:

Binary cache (bin/): platform-specific tool executables, keyed by {tool}/{version}/{platform}/{executable}. Each cached binary has a .sha256 sidecar written after a verified archive download. Cache hits verify the binary against this sidecar to detect local tampering.

HTTP response cache (http/): JSON API responses from PyPI and GitHub, keyed by {namespace}/{key}.json. Freshness is controlled by a per-caller TTL (seconds); stale entries remain on disk until auto-purge removes them.

Config cache (config/): generated tool configuration files, keyed by {tool}/{filename}. Overwritten on every invocation from the current [tool.X] section in pyproject.toml or bundled defaults. Passed to tools via explicit --config flags so repomatic never writes to the user’s repository.

Note

The cache module is intentionally a pure storage layer. It does not know about checksums, registries, API semantics, or tool specifications. All trust and freshness decisions belong to the caller.

repomatic.cache.CACHE_LIST_HEADER_DEFS: tuple[tuple[str, str], ...] = (('Type', 'type'), ('Name', 'name'), ('Detail', 'detail'), ('Size', 'size'), ('Age', 'age'))

Column definitions for the repomatic cache show table.

Lives beside the entry dataclasses it renders; the CLI derives its --sort-by choices from it.

class repomatic.cache.CachedFile(size, path, mtime)[source]

Bases: object

The filesystem facts every cached entry carries, whatever it holds.

The three caches (binaries, HTTP responses, tool configs) differ only in how they name an entry; everything the listing, the age filter and the purge loop need is here, so those all take a CachedFile and never care which subtree it came from.

Subclasses supply their own identity fields plus kind and scope.

size: int

File size in bytes.

path: Path

Absolute path to the cached file.

mtime: float

File modification time (seconds since epoch).

kind: ClassVar[str] = ''

The cache this entry belongs to, as the repomatic cache show table spells it.

property scope: str

The name a cache clean filter matches this entry on.

Doubles as the table’s subject column: the thing a reader identifies the entry by (--tool ruff, --namespace pypi) is the same thing the listing shows them, so one property serves both.

property detail: str

What distinguishes this entry from its siblings in the same scope.

is_fresh(max_age_days)[source]

Whether this entry is younger than the age cutoff.

A None cutoff keeps nothing: age-unfiltered clears delete every entry the caller’s other filters matched.

Return type:

bool

as_row()[source]

Render this entry as one repomatic cache show table row.

Return type:

tuple[str, str, str, str, str]

class repomatic.cache.CacheEntry(size, path, mtime, tool='', version='', platform='', executable='')[source]

Bases: CachedFile

A single cached binary with its metadata.

tool: str = ''

Tool name (registry key).

version: str = ''

Pinned version string.

platform: str = ''

Platform key (e.g., linux-x64, macos-arm64).

executable: str = ''

Executable filename.

kind: ClassVar[str] = 'binary'

The cache this entry belongs to, as the repomatic cache show table spells it.

property scope: str

The name a cache clean filter matches this entry on.

Doubles as the table’s subject column: the thing a reader identifies the entry by (--tool ruff, --namespace pypi) is the same thing the listing shows them, so one property serves both.

property detail: str

What distinguishes this entry from its siblings in the same scope.

class repomatic.cache.HttpCacheEntry(size, path, mtime, namespace='', key='')[source]

Bases: CachedFile

A single cached HTTP response with its metadata.

namespace: str = ''

Cache namespace (e.g., pypi, github-releases).

key: str = ''

Cache key within the namespace (e.g., requests, astral-sh/ruff).

kind: ClassVar[str] = 'http'

The cache this entry belongs to, as the repomatic cache show table spells it.

property scope: str

The name a cache clean filter matches this entry on.

Doubles as the table’s subject column: the thing a reader identifies the entry by (--tool ruff, --namespace pypi) is the same thing the listing shows them, so one property serves both.

property detail: str

What distinguishes this entry from its siblings in the same scope.

class repomatic.cache.ConfigCacheEntry(size, path, mtime, tool='', filename='')[source]

Bases: CachedFile

A single cached tool configuration file with its metadata.

tool: str = ''

Tool name (registry key).

filename: str = ''

Config filename (e.g., yamllint.yaml, biome.json).

kind: ClassVar[str] = 'config'

The cache this entry belongs to, as the repomatic cache show table spells it.

property scope: str

The name a cache clean filter matches this entry on.

Doubles as the table’s subject column: the thing a reader identifies the entry by (--tool ruff, --namespace pypi) is the same thing the listing shows them, so one property serves both.

property detail: str

What distinguishes this entry from its siblings in the same scope.

repomatic.cache.cache_dir()[source]

Resolve the cache root directory.

Precedence (highest to lowest):

  1. REPOMATIC_CACHE_DIR environment variable.

  2. cache.dir in [tool.repomatic].

  3. Platform-specific default.

Return type:

Path

Returns:

Absolute path to the cache root (may not exist yet).

repomatic.cache.cached_binary_path(name, version, platform_key, executable)[source]

Construct the cache path for a binary (does not check existence).

Parameters:
  • name (str) – Tool name.

  • version (str) – Pinned version.

  • platform_key (str) – Platform key (e.g., linux-x64).

  • executable (str) – Executable filename.

Return type:

Path

Returns:

Absolute path where the binary would be cached.

repomatic.cache.SIDECAR_SUFFIX = '.sha256'

Suffix of the digest sidecar stored beside each cached binary.

Part of the binary cache’s on-disk layout: the listers skip sidecars and the purger removes them along with their entry. Computing, writing, and verifying the digest itself stays with the caller (tool_runner), per the module note above.

repomatic.cache.binary_sidecar_path(binary_path)[source]

Return the digest sidecar path for a cached binary.

Parameters:

binary_path (Path) – Path to the cached binary.

Return type:

Path

Returns:

Path of the sidecar file next to it.

repomatic.cache.get_cached_binary(name, version, platform_key, executable)[source]

Return the cached binary path if it exists and is executable.

Does not verify the checksum. The caller is responsible for integrity checks since it owns the checksum value and the skip_checksum flag.

Parameters:
  • name (str) – Tool name.

  • version (str) – Pinned version.

  • platform_key (str) – Platform key.

  • executable (str) – Executable filename.

Return type:

Path | None

Returns:

Path to the cached binary, or None if not cached.

repomatic.cache.store_binary(name, version, platform_key, source)[source]

Copy an extracted binary into the cache atomically.

Writes to a temporary file in the target directory, then renames to the final name. This is atomic on POSIX (same-filesystem rename) and safe on Windows (Path.replace overwrites atomically).

Triggers auto_purge() after a successful store.

Parameters:
  • name (str) – Tool name.

  • version (str) – Pinned version.

  • platform_key (str) – Platform key.

  • source (Path) – Path to the extracted binary to cache.

Return type:

Path | None

Returns:

Path to the cached binary, or None when the cache is unwritable (a read-only cache root, a restricted CI mount): callers fall back to their staging copy, matching store_response() and store_config().

repomatic.cache.cache_info()[source]

List all cached binaries.

The bin/ layout is fixed at four levels ({tool}/{version}/{platform}/{executable}), so one glob walks it and the identity fields read straight off each path’s ancestry.

Return type:

list[CacheEntry]

Returns:

List of CacheEntry instances, sorted by tool name then version.

repomatic.cache.clear_cache(tool=None, max_age_days=None)[source]

Remove cached binaries.

Parameters:
  • tool (str | None) – If set, only remove entries for this tool. Otherwise remove all cached binaries.

  • max_age_days (int | None) – If set, only remove entries with mtime older than this many days. Otherwise remove all matching entries.

Return type:

tuple[int, int]

Returns:

Tuple of (files_deleted, bytes_freed).

repomatic.cache.get_cached_response(namespace, key, max_age_seconds)[source]

Return a cached HTTP response if it exists and is fresh.

Parameters:
  • namespace (str) – Cache namespace (e.g., pypi, github-releases).

  • key (str) – Cache key, may contain / for nested paths.

  • max_age_seconds (int) – Maximum age in seconds. Entries with mtime older than this are considered stale and ignored. <= 0 disables the cache (always returns None).

Return type:

bytes | None

Returns:

Raw cached response bytes, or None if not cached or stale.

repomatic.cache.store_response(namespace, key, data)[source]

Store an HTTP response in the cache atomically.

Uses the same write-to-temp-then-rename pattern as store_binary(). Triggers auto_purge() after a successful store.

Parameters:
  • namespace (str) – Cache namespace.

  • key (str) – Cache key, may contain / for nested paths.

  • data (bytes) – Raw response bytes to cache.

Return type:

Path | None

Returns:

Path to the cached response file, or None if the write failed (permissions, read-only filesystem, sandbox restrictions).

repomatic.cache.http_cache_info()[source]

List all cached HTTP responses.

Return type:

list[HttpCacheEntry]

Returns:

List of HttpCacheEntry instances, sorted by namespace then key.

repomatic.cache.clear_http_cache(namespace=None, max_age_days=None)[source]

Remove cached HTTP responses.

Parameters:
  • namespace (str | None) – If set, only remove entries in this namespace. Otherwise remove all cached responses.

  • max_age_days (int | None) – If set, only remove entries with mtime older than this many days. Otherwise remove all matching entries.

Return type:

tuple[int, int]

Returns:

Tuple of (files_deleted, bytes_freed).

repomatic.cache.store_config(tool_name, filename, content)[source]

Store a generated tool config in the cache atomically.

Uses the same write-to-temp-then-rename pattern as store_response(). Does not trigger auto_purge(): config files are tiny and overwritten on every invocation, so age-based pruning is unnecessary.

Parameters:
  • tool_name (str) – Tool name (registry key).

  • filename (str) – Config filename (e.g., yamllint.yaml).

  • content (str) – Config file content as text.

Return type:

Path | None

Returns:

Path to the cached config file, or None if the write failed (permissions, read-only filesystem, sandbox restrictions).

repomatic.cache.config_cache_info()[source]

List all cached tool configurations.

Return type:

list[ConfigCacheEntry]

Returns:

List of ConfigCacheEntry instances, sorted by tool name.

repomatic.cache.clear_config_cache(tool=None, max_age_days=None)[source]

Remove cached tool configurations.

Parameters:
  • tool (str | None) – If set, only remove entries for this tool. Otherwise remove all cached configurations.

  • max_age_days (int | None) – If set, only remove entries older than this many days, matching clear_cache() and clear_http_cache().

Return type:

tuple[int, int]

Returns:

Tuple of (files_deleted, bytes_freed).

repomatic.cache.cache_rows()[source]

List every cached file across the three caches, as table rows.

Backs repomatic cache show: each entry renders itself (CachedFile.as_row()), so the command stays a print call and a new cache kind shows up in the listing by existing.

Return type:

tuple[list[tuple[str, str, str, str, str]], int]

Returns:

(rows, total_size), rows ordered binaries, then HTTP responses, then tool configs.

repomatic.cache.auto_purge()[source]

Remove cached entries older than the configured TTL.

Called automatically after store_binary() and store_response(), and runs at most once per cache root per process (see _PURGED_ROOTS). Purges both binary and HTTP cache entries. Resolves the TTL from REPOMATIC_CACHE_MAX_AGE env var, then cache.max-age in [tool.repomatic], then the CacheConfig.max_age field default. Set to 0 to disable.

Return type:

None