fix(install): ship template-cli as raw wheel script; drop Python shim#7
Merged
Conversation
…#2 items 1+10) Previously the Python entry point `[project.scripts] template-python-rust-cmd = "template_python_rust_cmd.cli:main"` created a pip console-script `.exe` that subprocess-launched the staged `_bin/template-cli`. On Windows that pattern races the next shell prompt ahead of the child's stdout, because the Python shim returns to cmd.exe before the spawned native binary finishes flushing. Same class of bug fbuild fixed in FastLED/fbuild#747. Drop the shim. ci/build_wheel.py now post-processes the maturin-built wheel: opens the zip, injects the cargo-built `template-cli[.exe]` at `<name>-<ver>.data/scripts/template-cli[.exe]`, recomputes the RECORD row (sha256 + size), and stamps the Unix executable bit on the entry. Files in `.data/scripts/` are pip's canonical raw-script install location — pip drops them straight into the venv's `Scripts/` (Win) / `bin/` (POSIX) directory verbatim, with no Python wrapper for `.exe` files. Same mechanism cargo-dist and maturin's "bin" mode use. Removed: - `[project.scripts]` table from pyproject.toml. - `src/template_python_rust_cmd/cli.py` (the racy subprocess shim). - `src/template_python_rust_cmd/_bin/.gitkeep` + the gitignore lines that staged binary into the package data directory. - `action/cleanup/action.yml` step that rm'd the (now-nonexistent) `_bin/` staging directory. Verified end-to-end on Windows: - Fresh maturin wheel produced via `uv run --no-project --script ci/build_wheel.py`. - `unzip -l dist/*.whl` shows `template_python_rust_cmd-0.1.0.data/ scripts/template-cli.exe` (1.2 MB) — no `_bin/` entries. - `uv pip install` of that wheel into a fresh venv lands a `Scripts/ template-cli.exe` that `file` reports as `PE32+ executable` (NOT a Zip-archive console-script stub). - `cmd /c 'echo === BEFORE === & template-cli.exe --version & echo === AFTER ==='` prints `=== AFTER ===` AFTER the version output — acceptance criterion from issue #2 met. The `no-build-isolation-package` setting added in PR #5 was reverted in this PR: with maturin (vs. setuptools) the trade-off doesn't favor us — uv reuses a stale build env that lacks maturin, and the preview `extra-build-dependencies` mechanism is too fragile to ship in a template. The CARGO_TARGET_DIR pin from that PR stays — it already gives the cargo-incremental win without touching isolation. Closes #2 (items 1 + 10). Refs FastLED/fbuild#747. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This was referenced Jun 22, 2026
zackees
added a commit
that referenced
this pull request
Jun 22, 2026
…oses #9) (#10) Followup cleanup to #7 (drop Python CLI shim, ship raw wheel script). The package-side refactor worked at the wheel-build level but left stale source-tree references in two artifact-walking tools — same failure shape as fbuild#748 (a packaging refactor that worked at the wheel level but broke a tool walking the source tree a different way). Stale references found by `git grep '_bin\|template_python_rust_cmd\.cli'`: 1. `tests/test_cli.py` — imported `template_python_rust_cmd.cli. packaged_binary_path` (module deleted in #7). Whole file failed to collect with ImportError; the suite was silently 1 file short. 2. `ci/gates/action_surface.py::_binary_path()` — listed `src/template_python_rust_cmd/_bin/template-cli[.exe]` as its FIRST lookup candidate. That directory was removed in #7. Fallback to target/release worked locally but the gate doesn't honor CARGO_TARGET_DIR (pinned to ~/.template-python-rust-cmd/cargo-target/ wheel-build in #5), so it silently misses the binary on a wheel-build-driven runner. 3. `tests/README.md` — described `test_cli.py` as covering "the Python CLI shim's binary-discovery logic" (module gone). Fix: - `tests/test_cli.py` rewritten as a runtime contract check: probe PATH for `template-cli`, skip if absent (dev venv without install), otherwise assert it's invokable and produces non-empty --version output. Matches the new shipping mechanism (raw wheel script) which doesn't leave a source-tree probe target. - `ci/gates/action_surface.py::_binary_path()` now searches, in order: 1. $CARGO_TARGET_DIR/{release,debug}/ if set 2. ROOT/target/{release,debug}/ for the local ./test flow 3. PATH via shutil.which for pip/uv-installed binaries Updated the "no binary found" warning to match. - `tests/README.md` describes what test_cli.py actually does now. Verified: - `uv run pytest tests/test_cli.py tests/test_version.py tests/test_bindings.py -v` → 2 pass, 2 skip (test_cli skips because dev venv has no installed template-cli — expected behavior). - `./ci.sh test` → 34 pass, 2 skip, [test] ok. - `./ci.sh action_surface` → finds the binary, gate passes. Closes #9. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This was referenced Jun 22, 2026
zackees
added a commit
that referenced
this pull request
Jun 22, 2026
Followup to #7 (raw wheel script) and #9/#10 (test + gate cleanup). #9 fixed the tools that broke at runtime; this PR fixes the docs that broke at the human-reader level. Same failure shape as fbuild#748: a packaging refactor was correct at the wheel-build path but downstream readers walking artifacts a different way still saw the dead shape. Files touched (doc-only; no behavioral change): - README.md: tree diagram no longer shows cli.py/_bin/. Packaging section describes the actual raw-wheel-script mechanism. - CLAUDE.md: agent-routing doc now describes the post-#7 wheel layout + the pinned CARGO_TARGET_DIR build pipeline. No more cli.py shim invariants. - ENHANCE.md: invariants updated — "no Python shim, raw wheel script, re-adding [project.scripts] would re-introduce the Windows os.execv race" replaces the old shim invariants. - crates/template-cli/README.md: describes the inject_cli_into_wheel step instead of the deleted _bin/ staging step. - docs/ARCHITECTURE.md: package contents accurately reflect what's actually in src/template_python_rust_cmd/ today (no cli.py listed). - docs/RELEASE.md: build_wheel.py described as cargo → maturin → inject into .data/scripts/, not stage into _bin/. Verified: - `grep -rn '_bin\|template_python_rust_cmd\.cli\|cli\.py' README.md CLAUDE.md ENHANCE.md docs/ crates/template-cli/README.md` returns only historical-context references explicitly explaining the migration (acceptance-criterion-allowed). - `./ci.sh test` → 34 pass, 2 skip. - `./ci.sh action_yaml` → ok. - `./ci.sh action_surface` → ok. Closes #11. Refs #7, #9, fbuild#748. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The big one — same Windows stdout-ordering bug fbuild#747 just fixed, ported here.
Drop the
[project.scripts]Python entry point +cli.pysubprocess shim.ci/build_wheel.pynow post-processes the maturin-built wheel to inject the cargo-builttemplate-cli[.exe]at<name>-<ver>.data/scripts/with a recomputed RECORD row + Unix +x bit. Pip drops files from.data/scripts/straight into Scripts/bin verbatim — no Python wrapper for.exefiles.Also reverts
no-build-isolation-packagefrom PR #5 (kept the CARGO_TARGET_DIR pin from that PR). With maturin (vs. setuptools) the no-isolation trade-off doesn't work cleanly — uv reuses a build env lacking maturin and the previewextra-build-dependenciesmechanism is too fragile.Acceptance (all from #2)
unzip -l dist/*.whlshowstemplate_python_rust_cmd-0.1.0.data/scripts/template-cli.exe, no_bin/.file $(which template-cli)reportsPE32+ executable, NOT a Zip-archive console-script stub.cmd /c 'echo === BEFORE === & template-cli --version & echo === AFTER ==='prints=== AFTER ===AFTER the version line.Breaking change
The
template-python-rust-cmdcommand name is gone (it was the auto-generated console-script wrapper from[project.scripts]). Users should invoketemplate-clidirectly. Action consumers (uses: zackees/template-python-rust-cmd@v1) already usecommand -v template-cliso they're unaffected.Closes #2 (items 1 + 10).
🤖 Generated with Claude Code