Skip to content

Commit 7cbe281

Browse files
committed
All providers: make managed shim refresh idempotent
Brew / Npm / Pnpm / Goget providers all refreshed their managed ``bin_dir`` shim on every ``default_abspath_handler`` call (i.e. every ``load()``) by unconditionally ``unlink`` + ``symlink_to``. Even for symlinks -- where ``.resolve().stat()`` follows the link and returns the target's stable mtime -- this still churns the shim's inode on every load, which invalidates fingerprint caches keyed on inode and causes unnecessary filesystem thrash in tight lifecycle loops. Skip the unlink + rewrite when the existing symlink already resolves to ``target``. Matches the idempotency check already present in the base class ``_link_loaded_binary`` and the same fix just applied to Puppeteer/Playwright ``_refresh_symlink``.
1 parent c8ad32b commit 7cbe281

4 files changed

Lines changed: 36 additions & 0 deletions

File tree

abxpkg/binprovider_brew.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,15 @@ def _refresh_bin_link(
183183
except Exception:
184184
break
185185
walk_path = walk_path.parent
186+
# Idempotent refresh: skip when shim already points at target.
187+
# Rewriting on every load() bumps mtime and churns the inode,
188+
# which invalidates fingerprint caches unnecessarily.
189+
if link_path.is_symlink():
190+
try:
191+
if link_path.readlink() == Path(target):
192+
return TypeAdapter(HostBinPath).validate_python(link_path)
193+
except OSError:
194+
pass
186195
if link_path.exists() or link_path.is_symlink():
187196
link_path.unlink(missing_ok=True)
188197
link_path.symlink_to(target)

abxpkg/binprovider_goget.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,15 @@ def default_abspath_handler(
294294
assert bin_dir is not None
295295
link_path = bin_dir / str(bin_name)
296296
link_path.parent.mkdir(parents=True, exist_ok=True)
297+
# Idempotent refresh: skip when shim already points at target.
298+
# Rewriting on every load() bumps mtime and churns the inode,
299+
# which invalidates fingerprint caches unnecessarily.
300+
if link_path.is_symlink():
301+
try:
302+
if link_path.readlink() == Path(direct_abspath):
303+
return TypeAdapter(HostBinPath).validate_python(link_path)
304+
except OSError:
305+
pass
297306
if link_path.exists() or link_path.is_symlink():
298307
link_path.unlink(missing_ok=True)
299308
link_path.symlink_to(direct_abspath)

abxpkg/binprovider_npm.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,15 @@ def _refresh_bin_link(
377377
link_path = self._linked_bin_path(bin_name)
378378
assert link_path is not None, "_refresh_bin_link requires bin_dir to be set"
379379
link_path.parent.mkdir(parents=True, exist_ok=True)
380+
# Idempotent refresh: skip when shim already points at target.
381+
# Rewriting on every load() bumps mtime and churns the inode,
382+
# which invalidates fingerprint caches unnecessarily.
383+
if link_path.is_symlink():
384+
try:
385+
if link_path.readlink() == Path(target):
386+
return TypeAdapter(HostBinPath).validate_python(link_path)
387+
except OSError:
388+
pass
380389
if link_path.exists() or link_path.is_symlink():
381390
link_path.unlink(missing_ok=True)
382391
link_path.symlink_to(target)

abxpkg/binprovider_pnpm.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,15 @@ def _refresh_bin_link(
274274
link_path = self._linked_bin_path(bin_name)
275275
assert link_path is not None, "_refresh_bin_link requires bin_dir to be set"
276276
link_path.parent.mkdir(parents=True, exist_ok=True)
277+
# Idempotent refresh: skip when shim already points at target.
278+
# Rewriting on every load() bumps mtime and churns the inode,
279+
# which invalidates fingerprint caches unnecessarily.
280+
if link_path.is_symlink():
281+
try:
282+
if link_path.readlink() == Path(target):
283+
return TypeAdapter(HostBinPath).validate_python(link_path)
284+
except OSError:
285+
pass
277286
if link_path.exists() or link_path.is_symlink():
278287
link_path.unlink(missing_ok=True)
279288
link_path.symlink_to(target)

0 commit comments

Comments
 (0)