_makefile¶
rhiza_hooks._makefile
¶
Read the targets a repository's makefiles define.
Two hooks need this: check_makefile_targets asks whether the recommended
targets are present, and check_workflow_make_targets asks whether every target
CI invokes exists. Both questions start from the same parse, so the parser lives
here rather than in either hook.
Both are really the same question — "is this name defined?" — and since rhiza v1.4.0
neither can be answered from a list of names alone. The root Makefile is a shim whose
only real rule is help; everything else is served by a catch-all pattern rule that
forwards the goal to the rhiza-task CLI::
%: $(UVX) FORCE
@$(UVX) $(RHIZA_TASK) $(RHIZA_TASK_GOAL)
make test works there, and no test: rule exists. So the parse yields
:class:MakefileTargets, which carries the catch-all flag alongside the names and
answers the question itself in :meth:MakefileTargets.defines. Leaving each hook to
apply the flag would be leaving each hook to forget it.
The placement is deliberate. A console script's public surface is its main();
when one entrypoint imports a helper out of another, the dependency between the two
CLIs is invisible from either one's interface, and a change made for the sake of one
hook's command line silently reaches the other. A _-prefixed leaf module states
the shared part explicitly and imports nothing from the package.
MakefileTargets
dataclass
¶
What a set of makefiles can build: the names they define, and whether any name goes.
The two facts have to travel together. A repo whose Makefile is nothing but a
catch-all rule defines almost no names and can still build every one a caller
asks for, so a bare set of names is not enough to answer "is this target
defined?" — and both hooks ask exactly that question. :meth:defines is where
the answer lives, so the two cannot drift apart.
Source code in rhiza_hooks/_makefile.py
__bool__()
¶
Report whether anything was found — a repo with no makefile at all is falsy.
Both hooks decline to report against nothing: with no rules to compare, every invocation looks undefined, which is noise rather than signal. A lone catch-all rule is something, so it is truthy.
Source code in rhiza_hooks/_makefile.py
__or__(other)
¶
Merge what two makefiles define, so an include contributes both halves.
defines(target)
¶
Report whether target can be built.
A named rule defines it:
MakefileTargets(frozenset({"test"}), catch_all=False).defines("test") True MakefileTargets(frozenset({"test"}), catch_all=False).defines("fmt") False
So does a catch-all rule, whatever the name:
MakefileTargets(frozenset(), catch_all=True).defines("anything") True
Source code in rhiza_hooks/_makefile.py
collect_targets(repo_root)
¶
Return everything the root Makefile and its includes define, transitively.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
repo_root
|
Path
|
Root directory of the repository. |
required |
Returns:
| Type | Description |
|---|---|
MakefileTargets
|
The named targets and the catch-all flag, merged across every makefile |
MakefileTargets
|
reached. Falsy when there is no Makefile at all. |
Source code in rhiza_hooks/_makefile.py
extract_targets(content)
¶
Extract what one makefile's content defines.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
str
|
Contents of a Makefile |
required |
Returns:
| Type | Description |
|---|---|
MakefileTargets
|
The named targets found, and whether a catch-all rule is present. |