diff options
| author | Danilo M. <danix@danix.xyz> | 2026-06-26 12:17:46 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-06-26 12:17:46 +0200 |
| commit | c56915a117642341c65fa02fb5df96d0ee4d4c77 (patch) | |
| tree | 7eb8fc383adfab130e57270a254b7739011fba37 | |
| parent | 899ad73fc915fbfb9742cfbfa217fca130aaf063 (diff) | |
| download | mkwheels-c56915a117642341c65fa02fb5df96d0ee4d4c77.tar.gz mkwheels-c56915a117642341c65fa02fb5df96d0ee4d4c77.zip | |
docs: add CLAUDE.md
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| -rw-r--r-- | CLAUDE.md | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..c93c237 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,75 @@ +# mkwheels + +A standalone bash CLI that builds a **reproducible, pinned Python wheels +tarball** for a given package + version. Primary use: vendoring a Python +project's full dependency tree into a SlackBuild so the build installs into a +venv from local wheels with no network (the feroxbuster vendored-crates +pattern, applied to Python). + +## Layout + +``` +mkwheels # the whole CLI (single-file bash) +selftest # reproducibility check (builds six twice, asserts md5 match) +LICENSE # GPLv2 full text +README.md # user-facing usage + rationale +docs/superpowers/ # design spec + implementation plan +``` + +Single-file script by design. Keep it that way unless the tool genuinely +outgrows one file. + +## Invocation + +``` +mkwheels <pkg> <ver> [epoch] +``` + +- `<pkg> <ver>` — PyPI package and exact version. +- `[epoch]` — optional `SOURCE_DATE_EPOCH`. Omitted → auto-derived from the + PyPI release upload time (earliest file's `upload_time_iso_8601`), with a + warning. Pass it explicitly to override. +- `OUTPUT` env var — output dir (default: `$PWD`). + +Outputs `<pkg>-wheels-<ver>.tar.gz` + `requirements.txt`, prints md5 + epoch. + +## How it works + +1. Arg parse + required-tool check (`python3`+pip, `jq`, `curl`, `tar`, `gzip`, + `md5sum`). +2. Resolve `SOURCE_DATE_EPOCH` (explicit arg, else PyPI JSON via `jq`). +3. Throwaway venv + `pip download <pkg>==<ver>` into `wheels/`. +4. Emit pinned + hashed `requirements.txt` (audit record only, not the install + input). +5. Pack a byte-reproducible `.tar.gz`: sorted entries, `--mtime=@epoch`, + `--owner=0 --group=0 --numeric-owner`, `gzip -n`. + +## Reproducibility + +This is the whole point. The same `<pkg> <ver> [epoch]` MUST yield a +byte-identical tarball. The tar normalization (step 5) plus `set -o pipefail` +(so a `tar` failure can't be masked by `gzip` exiting 0) are what guarantees +it. + +**Git-sourced deps** (packages whose upstream pins a git URL, e.g. NetExec's +impacket) are frozen at download time: `pip download` resolves whatever is +current, and the tarball, once built, is the source of truth. The +`requirements.txt` records the exact resolved versions. + +## Conventions + +- `bash`, no third-party Python packages (the tool only drives `pip`). +- `set -eu` + `set -o pipefail`; temp workdir removed via `trap` on EXIT. +- GPLv2 (v2-only): per-file header, `Copyright (C) <year> Danilo M. + <danix@danix.xyz>`, License section in README. +- Commits GPG-signed. Work directly on master (small project). + +## Testing + +`./selftest` — builds `six` twice with a fixed epoch and asserts the two +tarballs are byte-identical. Run it after any change to the tar/packing logic. +Needs network (pypi.org). No test framework. + +## Maintainer + +danix — danix@danix.xyz |
