aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CLAUDE.md75
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