build-lock: honor CODEWHALE_BUILD_LOCK=0 and CODEWHALE_BUILD_LOCK_HELD itself

The script's docstring says nested invocations see
CODEWHALE_BUILD_LOCK_HELD and run unlocked, and its wait message tells
the user to "set CODEWHALE_BUILD_LOCK=0 to skip". Neither was true: only
scripts/dev-cache.sh checked the two variables before calling it. Every
direct caller (CI's self-hosted lock holder, agents wrapping npm or cargo
in build-lock.py) ignored both, and a nested direct call deadlocked on the
lock its own parent held.

The script now runs the command unlocked when CODEWHALE_BUILD_LOCK_HELD is
non-empty or CODEWHALE_BUILD_LOCK is one of dev-cache.sh's falsey values
(0, false, no, off, never, disabled), with the same exit-status mapping as
the locked path. The locked path is unchanged.

Evidence, scratch lock files only (never the real build.lock):
- committed script, lock held by `-- sleep 8`:
  CODEWHALE_BUILD_LOCK=0 call -> timeout (exit 124),
  CODEWHALE_BUILD_LOCK_HELD=1 call -> timeout (124),
  `build-lock.py L -- python3 build-lock.py L -- echo` -> deadlock (124)
- fixed script, same setups: all three exit 0 immediately; each of
  false/no/off/never/disabled exits 0
- still locks: CODEWHALE_BUILD_LOCK=1, yes, on, unset, and an empty
  CODEWHALE_BUILD_LOCK_HELD all wait while held (124 under a 2 s timeout)
  and run after release (exit 0); the locked child still sees
  CODEWHALE_BUILD_LOCK_HELD=1
- exit status: `sh -c 'exit 7'` -> 7 locked and bypassed; SIGTERM -> 143
  locked and bypassed; bad usage -> 2
- python3 -m py_compile and ruff check: clean

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
This commit is contained in:
Claude committed 2026-10-12 04:08:07 +00:00
1 parent 2cb33c4d04
commit e43d86e8be
1 file changed
+5
+5
View File
@@ -30,6 +30,11 @@ def main() -> int:
print("usage: build-lock.py <lock-file> -- <command> [args...]", file=sys.stderr)
return 2
lock_path, command = sys.argv[1], sys.argv[3:]
if os.environ.get("CODEWHALE_BUILD_LOCK_HELD") or os.environ.get(
"CODEWHALE_BUILD_LOCK", "1"
) in ("0", "false", "no", "off", "never", "disabled"):
status = subprocess.call(command)
return 128 - status if status < 0 else status
env = dict(os.environ, CODEWHALE_BUILD_LOCK_HELD="1")
try:
import fcntl