|
4 | 4 |
|
5 | 5 | import json |
6 | 6 | import os |
| 7 | +import shlex |
7 | 8 | import sys |
8 | 9 | import tempfile |
9 | 10 | import urllib.parse |
@@ -485,22 +486,25 @@ def _refresh_bin_link( |
485 | 486 | bin_name: BinName | HostBinPath, |
486 | 487 | target: HostBinPath, |
487 | 488 | ) -> HostBinPath: |
488 | | - """Recreate the managed shim symlink pointing at the resolved pnpm executable.""" |
| 489 | + """Recreate the managed shim wrapper pointing at the resolved pnpm executable.""" |
489 | 490 | link_path = self._linked_bin_path(bin_name) |
490 | 491 | assert link_path is not None, "_refresh_bin_link requires bin_dir to be set" |
491 | 492 | link_path.parent.mkdir(parents=True, exist_ok=True) |
492 | | - # Idempotent refresh: skip when shim already points at target. |
| 493 | + target_path = Path(target).expanduser().resolve(strict=False) |
| 494 | + wrapper = f'#!/bin/sh\nexec {shlex.quote(str(target_path))} "$@"\n' |
| 495 | + # Idempotent refresh: skip when shim already runs the target. |
493 | 496 | # Rewriting on every load() bumps mtime and churns the inode, |
494 | 497 | # which invalidates fingerprint caches unnecessarily. |
495 | | - if link_path.is_symlink(): |
| 498 | + if link_path.is_file() and not link_path.is_symlink(): |
496 | 499 | try: |
497 | | - if link_path.readlink() == Path(target): |
| 500 | + if link_path.read_text() == wrapper: |
498 | 501 | return TypeAdapter(HostBinPath).validate_python(link_path) |
499 | 502 | except OSError: |
500 | 503 | pass |
501 | 504 | if link_path.exists() or link_path.is_symlink(): |
502 | 505 | link_path.unlink(missing_ok=True) |
503 | | - link_path.symlink_to(target) |
| 506 | + link_path.write_text(wrapper) |
| 507 | + link_path.chmod(0o755) |
504 | 508 | return TypeAdapter(HostBinPath).validate_python(link_path) |
505 | 509 |
|
506 | 510 | def default_search_handler( |
|
0 commit comments