fix(ci): preserve exec bit on fbuild console script in wheel#135
fix(ci): preserve exec bit on fbuild console script in wheel#135
Conversation
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 20 minutes and 18 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
`pip install fbuild==2.1.18` produced a console script at `<env>/bin/fbuild` with the execute bit cleared, so every invocation of `fbuild --version` (or any other subcommand) failed with `Permission denied`. The only workaround was `chmod +x $(which fbuild)`. Root cause: `ci/publish.py::add_file` set `info.external_attr = exec_perms << 16` but left `info.create_system` at the `ZipInfo` default of `0` (DOS/Windows). In ZIP archives, the upper 16 bits of `external_attr` only encode Unix permissions when `create_system == 3`; otherwise they encode DOS file-attribute flags and every unpacker (pip, installer, unzip) ignores the permission bits. Result: the packaged fbuild binary never got `+x` on the installer's filesystem. Fix: set `info.create_system = 3` alongside the existing `external_attr` assignment in the `executable=True` branch. A round-trip sanity check (`zipfile → re-open → inspect`) confirms the mode survives as `0o755`. Refs #129. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8ddfcd9 to
c7fd824
Compare
Cuts a release containing the two P0 fixes landed since 2.1.19: - #134 "P0 regression — Operation not permitted (os error 1) on warm build" - #135 "preserve exec bit on fbuild console script in wheel" Both are currently blocking every FastLED uno build on GitHub Actions: the wheel's console script installs without +x, so CI can't even run `fbuild --version`, and the subsequent compile fails with `Operation not permitted (os error 1)` on every example. Also includes: - #131 rustfmt on lnk pipeline - #133 DiskCache leases.refcount schema migration - #128 AVR orchestrator fingerprint fast-path + telemetry (#127) - #126 FBUILD_WATCH_SET_CACHE_SECS env override - f8533d3 extend watch-set fingerprint fast-path to AVR orchestrator Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cuts a release containing the two P0 fixes landed since 2.1.19: - #134 "P0 regression — Operation not permitted (os error 1) on warm build" - #135 "preserve exec bit on fbuild console script in wheel" Both are currently blocking every FastLED uno build on GitHub Actions: the wheel's console script installs without +x, so CI can't even run `fbuild --version`, and the subsequent compile fails with `Operation not permitted (os error 1)` on every example. Also includes: - #131 rustfmt on lnk pipeline - #133 DiskCache leases.refcount schema migration - #128 AVR orchestrator fingerprint fast-path + telemetry (#127) - #126 FBUILD_WATCH_SET_CACHE_SECS env override - f8533d3 extend watch-set fingerprint fast-path to AVR orchestrator Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The 2.1.16 pin and the chmod/re-pin workarounds were added in iter1b to dodge #129 — the broken exec bit on the `fbuild` console script in the 2.1.18 wheel. That bug was fixed in #135 and released in 2.1.20 (verified: `pip install fbuild==2.1.20` on Windows now yields a working `fbuild --version`). This iteration removes: - the `fbuild==2.1.16` pin in the root pip install - the defensive `chmod +x` on the root venv's `fbuild` script - the `uv pip install --python .venv/bin/python "fbuild==2.1.16"` re-pin after `./install` / `uv sync` - the defensive `chmod +x` on the FastLED venv's `fbuild` script Also tightens the smoke check: `fbuild --version` is now `set -e` fatal instead of `|| true`, since the whole point of this iter is that the console script is back to working. CACHE_BUST bumped to force a cold run — first cold measurement on fbuild 2.1.20 and confirmation in CI (Linux) that the 2.1.20 wheel holds up end-to-end through toolchain materialization + full examples compile. Prior iter1b numbers were on 2.1.16; new baseline to follow. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2.1.20 shipped with mode=0o755 on the `fbuild` / `fbuild-daemon`
console scripts but with external_attr=0x01ed0000 — i.e. the mode
bits were set correctly but the file-type bit (S_IFREG) was zero.
pip's wheel installer calls stat.S_ISREG() on the upper 16 bits of
external_attr before deciding whether to apply the script's mode;
without the IFREG bit that test returns False, pip falls back to
umask defaults (0o644), and the binary lands on disk without +x:
/opt/hostedtoolcache/Python/3.12.13/x64/bin/fbuild:
Permission denied (exit code 126)
Windows doesn't care about exec bits on .exe files, which is why
2.1.20 looked fine on `uv tool install fbuild==2.1.20` on Windows
but was broken for every Linux/macOS user. It's also the root
cause of #129 — #135's "preserve exec bit" fix set
the mode but not the file-type bit.
Reference: uv / ruff / maturin-built wheels all have
external_attr=0x81ed0000 (S_IFREG | 0o755) on their script entries.
Verified locally by rebuilding the Linux x86_64 wheel against the
existing binary artifact: new external_attr=0x81ed0000, IFREG=True.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2.1.20 shipped with mode=0o755 on the `fbuild` / `fbuild-daemon`
console scripts but with external_attr=0x01ed0000 — i.e. the mode
bits were set correctly but the file-type bit (S_IFREG) was zero.
pip's wheel installer calls stat.S_ISREG() on the upper 16 bits of
external_attr before deciding whether to apply the script's mode;
without the IFREG bit that test returns False, pip falls back to
umask defaults (0o644), and the binary lands on disk without +x:
/opt/hostedtoolcache/Python/3.12.13/x64/bin/fbuild:
Permission denied (exit code 126)
Windows doesn't care about exec bits on .exe files, which is why
2.1.20 looked fine on `uv tool install fbuild==2.1.20` on Windows
but was broken for every Linux/macOS user. It's also the root
cause of #129 — #135's "preserve exec bit" fix set
the mode but not the file-type bit.
Reference: uv / ruff / maturin-built wheels all have
external_attr=0x81ed0000 (S_IFREG | 0o755) on their script entries.
Verified locally by rebuilding the Linux x86_64 wheel against the
existing binary artifact: new external_attr=0x81ed0000, IFREG=True.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2.1.20 shipped with mode=0o755 on the `fbuild` / `fbuild-daemon`
console scripts but with external_attr=0x01ed0000 — i.e. the mode
bits were set correctly but the file-type bit (S_IFREG) was zero.
pip's wheel installer calls stat.S_ISREG() on the upper 16 bits of
external_attr before deciding whether to apply the script's mode;
without the IFREG bit that test returns False, pip falls back to
umask defaults (0o644), and the binary lands on disk without +x:
/opt/hostedtoolcache/Python/3.12.13/x64/bin/fbuild:
Permission denied (exit code 126)
Windows doesn't care about exec bits on .exe files, which is why
2.1.20 looked fine on `uv tool install fbuild==2.1.20` on Windows
but was broken for every Linux/macOS user. It's also the root
cause of #129 — #135's "preserve exec bit" fix set
the mode but not the file-type bit.
Reference: uv / ruff / maturin-built wheels all have
external_attr=0x81ed0000 (S_IFREG | 0o755) on their script entries.
Verified locally by rebuilding the Linux x86_64 wheel against the
existing binary artifact: new external_attr=0x81ed0000, IFREG=True.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Fixes the packaging half of #129. After
pip install fbuild==2.1.18, the installed console script at<env>/bin/fbuildhad the execute bit cleared:The only workaround was
chmod +x $(which fbuild).Root cause
ci/publish.py::add_filebuilds the wheel viazipfile.ZipInfoand setsinfo.external_attr = exec_perms << 16but leavesinfo.create_systemat the default value of0(DOS/Windows). In the ZIP format, the upper 16 bits ofexternal_attrare interpreted as Unix permissions only whencreate_system == 3(Unix); otherwise they encode DOS file-attribute flags and every unpacker — pip, installer, unzip — ignores the mode and installs the file without+x.That's why the fbuild binary shipped through PyPI had no execute bit on Linux/macOS.
Fix
Set
info.create_system = 3alongside the existingexternal_attrassignment in theexecutable=Truebranch ofadd_file. A round-trip sanity check (zipfile → re-open → inspect) confirms the mode survives as0o755.Test plan
+xon Linux/macOS — verified by end-to-endpip install fbuild && fbuild --versionafter release.🤖 Generated with Claude Code