README: drop the tooling attribution, document the entrypoints (closes #21)
All checks were successful
check / check (push) Successful in 1m1s

Four independent README defects, one docs-only pass. README.md is the
only file touched: the issue's definition of done restricts the change
to the README, so TODO.md is deliberately not updated here.

Remove the trailing attribution sentence from the Description. The
paragraph above it already carries authorship and licence, so nothing
is lost, and the naming it carried is not wanted in this repo's output.

Add the required Entrypoints section. House policy wants a README
section that opens by stating adherence to Scripts to Rule Them All,
links the standard, and documents every script/ entrypoint; grep for
"script/" in the README previously returned nothing, though all twelve
entrypoints exist and the Gitea workflow runs script/cibuild. Each
entry is written from reading the script, not from its name. Two
behaviours are called out because they are unusual and were hard-won:
script/bootstrap version-checks golangci-lint against its pin and
verifies the install is the copy PATH resolves rather than a shadowed
one, and script/docker and script/cibuild pass a fresh CHECK_EPOCH so
the Dockerfile's gate layers cannot be served from cache, which is
what keeps a green build from being one that ran nothing.

Fix the stale Build section. Every Makefile target became a thin shim
into script/, so the "Makefile is the single source of truth" claim is
no longer true; point at script/ instead. Document make bootstrap and
make setup, which exist and were undocumented. Drop the make clean
clause about a legacy local files.dat, a file nothing produces any
more; the remaining files.dat references in Makefile, .gitignore and
.dockerignore are #22 and are untouched.

Fix the scan summary example, which showed 123456 files seen against
components summing to 123400. removed is deliberately excluded from
the total, as the following paragraph says and as scan.go implements,
so the total is what was wrong.
This commit is contained in:
2026-08-09 07:51:31 +00:00
parent a102b8fb06
commit 9322e8ddee

View File

@@ -16,9 +16,6 @@ expensive. `scan` maintains a persistent SQLite database of file
signatures that survives between runs, so it can be run from cron and
the reports can be generated at any time from the most recent scan.
This tool was created by [@sneak](https://sneak.berlin) to scratch an itch,
using Claude Code/Fable.
This README is the complete and authoritative specification.
## Getting Started
@@ -283,7 +280,7 @@ the workers.
files seen this run broken down by disposition, plus skips:
```
scan: 123456 files seen (1200 added, 34 updated, 56 removed, 122166 unchanged), 3 skipped
scan: 123400 files seen (1200 added, 34 updated, 56 removed, 122166 unchanged), 3 skipped
```
(`removed` counts deleted database records, which are not part of the
@@ -443,12 +440,80 @@ Additional requirements:
- `2`: usage error (including `scan` with no `PATH` operand and
`report`/`trees` with any positional argument).
## Entrypoints
This repository adheres to the
[Scripts to Rule Them All](https://github.com/github/scripts-to-rule-them-all)
standard: the normalized executables in `script/` are the entrypoints
for the development workflow, and the `Makefile` targets are thin
shims that call them. Every script is POSIX `sh`, resolves the
repository root itself so it can be run from any working directory,
and may be invoked directly. The provided entrypoints are:
- `script/bootstrap` — install everything needed to build and
develop this repository, idempotently, assuming nothing is
present. `git`, `make`, and `go` come from the first of nix, apt,
brew, or apk found on the host, and are presence-checked only.
`golangci-lint` is treated differently: it is checked against the
version pinned in the script (the version the `Dockerfile` lint
stage runs) and reinstalled with `go install` whenever the
installed version differs — older or newer, not merely absent —
because a host on any other version lints against different rules
than CI. After installing, the script verifies the pin against the
`golangci-lint` that `PATH` actually resolves; if a different copy
shadows the install, bootstrap fails, naming both the install
directory and the shadowing binary, rather than reporting a
success the gate would not honour. Ends with `go mod download`.
- `script/setup` — make a fresh clone ready for development: runs
`script/bootstrap`, then `script/install-precommit`.
- `script/projectname` — print this project's name (`sfdupes`).
Scripts that need the name call it, so they stay identical across
repositories.
- `script/test` — run the test suite with a 30-second timeout and
coverage enabled, rerunning verbosely on failure so the logs show
which test failed.
- `script/lint` — run `golangci-lint` over the module with the
repository's `.golangci.yml`.
- `script/fmt` — format the Go sources in place (`gofmt -s -w`).
Markdown is not formatted.
- `script/fmt-check` — the read-only counterpart of `script/fmt`:
prints any unformatted file and exits non-zero instead of writing.
- `script/check` — run `script/test`, `script/lint`, and
`script/fmt-check`, in that order. Modifies nothing.
- `script/docker` — build the Docker image, tagged with the name
from `script/projectname`. The `Dockerfile` runs the gates as
build steps, so this is also the check a developer or reviewer
runs by hand.
- `script/cibuild` — build the Docker image untagged. This is what
the Gitea workflow runs on push; because the gates run as build
steps, a successful build implies the repository is green.
- `script/precommit` — run by the git pre-commit hook: `go mod tidy`
must be a no-op (a resulting change to `go.mod` or `go.sum` fails
the commit), then `script/check`.
- `script/install-precommit` — install the git pre-commit hook that
runs `script/precommit`. The hook is written to the common git
directory, so the main checkout and every worktree share it.
`script/docker` and `script/cibuild` both pass a freshly computed
`CHECK_EPOCH` build argument, and the `Dockerfile`'s gate steps
reference it. Without that, an unchanged tree lets Docker serve the
gate layers from cache and the build exits 0 having executed no tests
and no lint — a green it never earned. `CHECK_EPOCH` invalidates the
gate layers on every run while leaving the pinned base images and the
dependency layers cached.
## Build
The `Makefile` is the single source of truth for all operations:
The `script/` entrypoints above are where the implementations live;
the `Makefile` targets are shims onto them, except `build`, which
carries the compile recipe:
- `make` / `make build` — build the `sfdupes` binary (cgo
disabled); building is the default target.
- `make bootstrap` — install the build and development
dependencies.
- `make setup` — prepare a fresh clone: `bootstrap` plus the
pre-commit hook.
- `make test` — run the test suite (30-second timeout; reruns with
`-v` on failure).
- `make lint` — run `golangci-lint` with the repo config.
@@ -458,7 +523,7 @@ The `Makefile` is the single source of truth for all operations:
- `make docker` — build the Docker image, which runs `make check` as
a build stage.
- `make hooks` — install the pre-commit hook.
- `make clean` — remove the binary and any legacy local `files.dat`.
- `make clean` — remove the binary.
### Definition of done