Skip to content

Commit b47f7bb

Browse files
committed
Puppeteer/Playwright _refresh_symlink: idempotent when shim already matches
On macOS, chrome/chromium ship as ``.app`` bundles so the managed ``bin_dir`` shim is a shell-script launcher (``#!/bin/sh\nexec <path>``), not a symlink. ``default_abspath_handler`` calls ``_refresh_symlink`` on every ``load()``, which unconditionally deleted + rewrote the shim -- bumping its mtime each time. Tests that call ``install()`` then ``assert_shallow_binary_loaded`` (which re-stats the shim via ``get_abspath(no_cache=True)``) then observed ``loaded_mtime != resolved.stat().st_mtime_ns``, failing across every macOS puppeteer/ playwright test (8 playwright tests + test_chrome_alias in puppeteer). Linux uses a real symlink and ``.resolve().stat()`` follows it to the browser binary, whose mtime is stable -- so Linux CI was already green. Skip the unlink+rewrite when the existing shim already points at ``target`` (symlink target equals path, or shell-script contents match what we'd write). ``install()`` still always resolves the fresh path, and a stale shim pointing at an old target still gets replaced.
1 parent 38982f9 commit b47f7bb

2 files changed

Lines changed: 52 additions & 12 deletions

File tree

abxpkg/binprovider_playwright.py

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -561,16 +561,36 @@ def _refresh_symlink(self, bin_name: str, target: Path) -> Path:
561561
)
562562
link = self.bin_dir / bin_name
563563
link.parent.mkdir(parents=True, exist_ok=True)
564-
if link.exists() or link.is_symlink():
565-
link.unlink(missing_ok=True)
566564
# On macOS the executable is buried inside a ``.app`` bundle, so
567565
# write a tiny shell shim instead of a symlink (same pattern as
568566
# PuppeteerProvider).
569-
if os.name == "posix" and ".app/Contents/MacOS/" in str(target):
570-
link.write_text(
571-
f'#!/bin/sh\nexec {shlex.quote(str(target))} "$@"\n',
572-
encoding="utf-8",
573-
)
567+
use_shell_shim = os.name == "posix" and ".app/Contents/MacOS/" in str(target)
568+
desired_script = (
569+
f'#!/bin/sh\nexec {shlex.quote(str(target))} "$@"\n'
570+
if use_shell_shim
571+
else None
572+
)
573+
# Idempotent refresh: leave the shim untouched when it already
574+
# points at ``target``. Rewriting on every ``load()`` would bump
575+
# the shim's mtime (shell-script case), which breaks callers
576+
# that stat the shim to validate a freshly-installed binary.
577+
if link.is_symlink():
578+
try:
579+
if os.readlink(link) == str(target):
580+
return link
581+
except OSError:
582+
pass
583+
elif use_shell_shim and link.is_file():
584+
try:
585+
if link.read_text(encoding="utf-8") == desired_script:
586+
return link
587+
except OSError:
588+
pass
589+
if link.exists() or link.is_symlink():
590+
link.unlink(missing_ok=True)
591+
if use_shell_shim:
592+
assert desired_script is not None
593+
link.write_text(desired_script, encoding="utf-8")
574594
link.chmod(0o755)
575595
return link
576596
link.symlink_to(target)

abxpkg/binprovider_puppeteer.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -491,13 +491,33 @@ def _refresh_symlink(self, bin_name: str, target: Path) -> Path:
491491
assert bin_dir is not None
492492
link_path = bin_dir / bin_name
493493
link_path.parent.mkdir(parents=True, exist_ok=True)
494+
use_shell_shim = os.name == "posix" and ".app/Contents/MacOS/" in str(target)
495+
desired_script = (
496+
f'#!/bin/sh\nexec {shlex.quote(str(target))} "$@"\n'
497+
if use_shell_shim
498+
else None
499+
)
500+
# Idempotent refresh: leave the shim untouched when it already
501+
# points at ``target``. Rewriting on every ``load()`` would bump
502+
# the shim's mtime (shell-script case), which breaks callers
503+
# that stat the shim to validate a freshly-installed binary.
504+
if link_path.is_symlink():
505+
try:
506+
if os.readlink(link_path) == str(target):
507+
return link_path
508+
except OSError:
509+
pass
510+
elif use_shell_shim and link_path.is_file():
511+
try:
512+
if link_path.read_text(encoding="utf-8") == desired_script:
513+
return link_path
514+
except OSError:
515+
pass
494516
if link_path.exists() or link_path.is_symlink():
495517
link_path.unlink(missing_ok=True)
496-
if os.name == "posix" and ".app/Contents/MacOS/" in str(target):
497-
link_path.write_text(
498-
f'#!/bin/sh\nexec {shlex.quote(str(target))} "$@"\n',
499-
encoding="utf-8",
500-
)
518+
if use_shell_shim:
519+
assert desired_script is not None
520+
link_path.write_text(desired_script, encoding="utf-8")
501521
link_path.chmod(0o755)
502522
return link_path
503523
link_path.symlink_to(target)

0 commit comments

Comments
 (0)