aboutsummaryrefslogtreecommitdiffstats
path: root/Makefile
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-17 14:52:14 +0200
committeruser <user@clank>2026-08-17 14:52:14 +0200
commitc9f357d0a138bb77ec344adb3de3ff0889796c51 (patch)
tree33fe534a5140c2362774b42175dabba8e0a1b670 /Makefile
parentsl0ppty: make tools, and a ruff version that cannot drift (diff)
downloadslosh-c9f357d0a138bb77ec344adb3de3ff0889796c51.tar.gz
slosh-c9f357d0a138bb77ec344adb3de3ff0889796c51.tar.xz
slosh-c9f357d0a138bb77ec344adb3de3ff0889796c51.zip
sl0ppty: the make tools the last commit described
The previous commit shipped the documentation for `make tools` and the `.gitignore` line for the venv it creates, and not the target itself. A `git reset --hard`, undoing a throwaway probe commit, took the working tree with it -- which is what `--hard` does. The `.gitignore` line was noticed missing and rewritten; the three files it was standing next to were not, so `docs/design.md` has been describing a target that did not exist. This is that target. `ruff` is not a system package on most machines, and `pip install --user ruff` is refused outright on a distro python (PEP 668): $ make tools ruff 0.16.3 in .venv survives make clean; rm -rf .venv to start over clang-format stays a system package, because everywhere it is one; `make tools` says so when it is missing rather than pretending it handled it. **The venv is looked in before `$PATH`, and that order is the point.** `ruff.toml` now pins the version with ruff's own `required-version`, so a ruff of the wrong one refuses to run and names both versions. Preferring `$PATH` would then strand somebody with 0.14 from their package manager and 0.16.3 sitting in the `.venv` the repo just built them -- refused by the tool, with the fix on disk and nothing looking at it. Tested with exactly that, for `make fmt-check` and for the hook. The pin exists because a formatter whose output moves between releases turns "formatted" into "formatted by whoever committed last", and the diff lands on the next person to touch the file. Bumping it is one line in `ruff.toml`, one in the Makefile, and a reformat commit -- the honest cost of a new version. The hook resolves ruff the same way, off `git rev-parse --show-toplevel` so it works from a subdirectory, and its message when ruff is missing now says `make tools`. Verified from a deleted `.venv`: `make fmt` stops with `ruff not found. run: make tools`; after `make tools` both `fmt` and `fmt-check` work with nothing on `$PATH`; `make fmt` over the whole tree changes nothing, so the pinned version agrees with what is committed; the hook formats a staged Python file through the venv, and still does with 0.14.0 ahead of it on `$PATH`. The hook was tested by running `.githooks/pre-commit` directly against a staged file. The obvious way -- a real probe commit -- needs the working tree clean to be meaningful, and getting there is what caused the mess this commit is repairing.
Diffstat (limited to 'Makefile')
-rw-r--r--Makefile31
1 files changed, 26 insertions, 5 deletions
diff --git a/Makefile b/Makefile
index 927e8c7..98a1b59 100644
--- a/Makefile
+++ b/Makefile
@@ -53,7 +53,7 @@ else
endif
.PHONY: all clean vendor run test retest test-live test-all smoke help coverage \
- docs fmt fmt-check hooks
+ docs fmt fmt-check hooks tools
.DEFAULT_GOAL := help
help: ## show this
@@ -251,18 +251,39 @@ CSRC := $(shell git ls-files '*.c' '*.h' 2>/dev/null | grep -v '^vendor/')
PYSRC := $(shell git ls-files '*.py' 2>/dev/null | grep -v '^vendor/') \
contrib/coverage contrib/gen-docs contrib/shader-repl
+# clang-format is a system package. ruff usually is not, and `pip install --user`
+# is refused outright on a distro python (PEP 668), so `make tools` puts it in a
+# venv here and everything looks there *first* -- before $$PATH, so that a system
+# ruff of the wrong version cannot strand somebody whose venv has the right one.
+# The version is pinned in ruff.toml as well, where ruff enforces it itself.
+RUFF_VERSION := 0.16.3
+VENV := .venv
+RUFF = $(if $(wildcard $(VENV)/bin/ruff),$(VENV)/bin/ruff,$(shell command -v ruff 2>/dev/null))
+no-ruff = { echo "ruff not found. run: make tools"; exit 1; }
+
+tools: ## install the formatters (a venv with ruff)
+ $(Q)python3 -m venv $(VENV)
+ $(Q)$(VENV)/bin/pip install --quiet --disable-pip-version-check \
+ ruff==$(RUFF_VERSION)
+ @printf ' %s\n' "$$($(VENV)/bin/ruff --version) in $(VENV)"
+ @command -v clang-format >/dev/null 2>&1 \
+ || echo " note: clang-format is missing (apt install clang-format)"
+ @echo " survives make clean; rm -rf $(VENV) to start over"
+
fmt: ## format the C and Python in place
+ @test -n "$(RUFF)" || $(no-ruff)
$(Q)clang-format -i $(CSRC)
- $(Q)ruff check -q --select I --fix $(PYSRC)
- $(Q)ruff format -q $(PYSRC)
+ $(Q)$(RUFF) check -q --select I --fix $(PYSRC)
+ $(Q)$(RUFF) format -q $(PYSRC)
$(say) " [FMT] $(words $(CSRC)) C, $(words $(PYSRC)) Python"
fmt-check: ## ...or just say what is not formatted
+ @test -n "$(RUFF)" || $(no-ruff)
@bad=$$(for f in $(CSRC); do \
clang-format "$$f" | cmp -s - "$$f" || echo "$$f"; \
done); \
- pybad=$$(ruff format -q --check $(PYSRC) 2>&1 | sed -n 's/^Would reformat: //p'; \
- ruff check -q --select I $(PYSRC) 2>/dev/null | sed -n 's/:.*//p' | sort -u); \
+ pybad=$$($(RUFF) format -q --check $(PYSRC) 2>&1 | sed -n 's/^Would reformat: //p'; \
+ $(RUFF) check -q --select I $(PYSRC) 2>/dev/null | sed -n 's/:.*//p' | sort -u); \
all=$$(printf '%s\n%s\n' "$$bad" "$$pybad" | sed '/^$$/d' | sort -u); \
if [ -n "$$all" ]; then \
echo "not formatted:"; echo "$$all" | sed 's/^/ /'; \