repomatic.tooling.runner module¶
Unified tool runner with managed config resolution.
Provides repomatic run <tool>: a single entry point that installs an
external tool at a pinned version, resolves its configuration through a strict
4-level precedence chain, translates [tool.X] sections from
pyproject.toml into the tool’s native format, and invokes the tool with
the resolved config. The tool catalog it drives (ToolSpec entries, pinned
versions, checksums) lives in tooling/registry.py, and tooling/binaries.py
installs the binary tools.
Important
Config resolution precedence (first match wins, no merging):
Native config file: the tool’s own config file in the repo.
``[tool.X]`` in ``pyproject.toml``: translated to the native format.
Bundled default: from
repomatic/data/.Bare invocation: no config at all.
- repomatic.tooling.runner.GIT_DIRECTORY = '.git'¶
Directory
_digest_targetsleaves out of the tree it walks.No tool rewrites a file there, and another process can: an editor that refreshes the index during a run would read as a file the tool rewrote.
- repomatic.tooling.runner.LOCK_POLL_SECONDS = 0.1¶
Delay between two attempts to take a lock Windows reported as held.
Windows has no blocking lock call that waits indefinitely:
msvcrt.LK_LOCKgives up after ten one-second attempts, so_acquire_lockpolls instead.
- repomatic.tooling.runner.NPM_INSTALL_FLAGS = ('--ignore-scripts', '--no-progress', '--no-update-notifier', '--no-fund', '--no-audit')¶
Flags of every
npm installrepomatic runs.--ignore-scriptsskips thepreinstall,installandpostinstallscripts of the package and of its whole transitive tree: the install-time vector behind most npm supply-chain worms. It is safe here because the npm backend only installs a repomatic-pinned, cooldown-gated tool, where no install script is needed.--no-auditstops npm from sending the resolved dependency tree to the audit endpoint of the registry on every install.The install of the pinned npm that installs the tool carries them too: see
_install_npm().
- repomatic.tooling.runner.TOOL_CRASH_EXIT_CODE = 70¶
Exit code reported when a tool contradicts its own rewrite status.
EX_SOFTWAREfromsysexits.h: an internal error in the tool being run. Deliberately distinct from the code a formatter uses to say “I reformatted a file”, so a crash cannot pass for a rewrite. Seerewrite_exit_code.
- class repomatic.tooling.runner.ConfigLevel(*values)[source]¶
Bases:
IntEnumPrecedence level of a tool’s configuration: the first one present wins.
- NATIVE = 1¶
The tool’s own config file in the repository.
- PYPROJECT = 2¶
The tool’s
[tool.X]table inpyproject.toml.
- BUNDLED = 3¶
The default repomatic bundles in
repomatic/data/.
- BARE = 4¶
No configuration: the tool runs on its own defaults.
- class repomatic.tooling.runner.ConfigSource(spec, level, native_file=None, table=None)[source]¶
Bases:
objectThe configuration a tool resolves to, as the precedence walk finds it.
Caution
The levels do not merge. The walk stops at its first hit, so a native config file or a
[tool.X]section replaces the bundled default in full rather than layering on top of it. A downstream repo overriding one rule must restate every bundled rule it wants to keep, and gains nothing when the bundled default later grows a rule.labelnames such a shadowing config, sorepomatic run --listshows the loss.- level: ConfigLevel¶
The level that wins.
- native_file: Path | None = None¶
The config file of the repository, at
ConfigLevel.NATIVE.
- table: dict[str, Any] | None = None¶
The
[tool.X]table, atConfigLevel.PYPROJECT.The live table of the parsed
pyproject.toml, atomlrt.Table. It keeps its comments for the formats that can carry them (seeserialize()). The parse is shared, so the table is read-only.
- repomatic.tooling.runner.resolve_config(spec)[source]¶
Resolve config for a tool using the 4-level precedence chain.
See
ConfigSourcefor the walk, and why its levels do not merge.- Parameters:
spec (
ToolSpec) – Tool specification.- Return type:
- Returns:
Tuple of (extra CLI args for config, path to clean up). The path is
Nonewhen no cleanup is needed (cache-based configs persist across runs). Non-Nonepaths are CWD files written for tools that have no--configflag.
- repomatic.tooling.runner.resolve_default_args(spec)[source]¶
Build the argument batches for a bare
repomatic run <tool>.Combines
default_argswith the file list named bydefault_paths, splitting into one batch per file whenper_fileis set.- Parameters:
spec (
ToolSpec) – The tool to resolve defaults for.- Return type:
- Returns:
One argument list per invocation; a single empty-argument batch when the tool declares no defaults, so the caller runs it bare as before.
Nonewhen the tool wants targets and the repository holds none, which means skip the tool rather than invoke it pathless.
- repomatic.tooling.runner.run_tool(name, extra_args=(), version=None, checksum=None, skip_checksum=False, no_cache=False)[source]¶
Run an external tool with managed config resolution.
With no extra_args, a tool declaring
default_argsordefault_pathsruns the invocation CI performs, resolved in-process byresolve_default_args(). Any explicit argument suppresses that entirely and is passed through as before.- Parameters:
name (
str) – Tool name (must be inTOOL_REGISTRY).extra_args (
Sequence[str]) – Extra arguments passed through to the tool.checksum (
str|None) – Override the SHA-256 checksum for the current platform.skip_checksum (
bool) – Skip SHA-256 verification entirely.no_cache (
bool) – Bypass the binary cache whenTrue.
- Return type:
- Returns:
The tool’s exit code; the first non-zero one when the defaults resolved to several invocations. A tool declaring
rewrite_exit_codereports0for a rewrite it performed, andTOOL_CRASH_EXIT_CODEfor one it did not.- Raises:
ValueError – If no tool goes by name.
ToolInstallError – If the tool or one of its companions cannot be installed.
- repomatic.tooling.runner.verify_via_write_path(name, extra_args=(), **run_kwargs)[source]¶
Check a
post_processtool’s formatting without touching the tree.A tool pairing
post_processwithcheck_flagshas no trustworthy check mode: the fixup only runs on the write path, so the check status can flag drift the write path would reconcile, or miss drift it would introduce (seecheck_flags). This runs the write path against throwaway copies instead, then compares, which is the only authoritative answer.Important
The copies are made inside the working directory, not in the system temp area. Formatters discover their config by walking up from each file, so a copy parked outside the repository resolves a different config and silently reports drift that does not exist.
The working tree is never written to: only the copies are formatted, and they are removed before returning.
- Parameters:
name (
str) – Tool name, as inrun_tool().extra_args (
Sequence[str]) – Arguments for the tool. Any existing path among them is copied and rewritten to its copy; check flags are dropped, since they would defeat the write path this relies on. Every other argument is passed through untouched. Empty resolves the tool’s registry defaults, the same setrun_tool()would have run, flattened into one batch: the copies are per-path already, so aper_filesplit would only cost extra invocations.run_kwargs (
Any) – Forwarded verbatim torun_tool().
- Return type:
- Returns:
(exit_code, drifted), whereexit_codeis0when every target is already formatted and1otherwise, anddriftednames the paths the write path would have changed. A tool that fails on the copies yields its own exit code and no drift, since it measured nothing. So does a call with no existing path to copy, which yields2, and a path that cannot be copied, which is logged and yields2too.- Raises:
ValueError – If no tool goes by name.
- repomatic.tooling.runner.find_unmodified_configs(root=None)[source]¶
Find native config files identical to their bundled defaults.
Iterates over every tool in
TOOL_REGISTRYthat has adefault_config. For each, checks whether any of itsnative_config_filesexists on disk and is content-identical to the bundled default after trailing-whitespace normalization.The normalization (
rstrip() + "\n") matches the convention used by_init_config_fileswhen writing files duringinit.- Parameters:
root (
Path|None) – Directory the relative config paths resolve against. Defaults to the working directory;run_initpasses itsoutput_dirso the scan and the deletion the CLI derives from it (--delete-unmodified) agree on one tree.- Return type:
- Returns:
List of
(tool_name, relative_path)tuples for each unmodified file found.