diff --git a/plain-code/plain/code/oxc.py b/plain-code/plain/code/oxc.py index 9e284bdb78..35d8d33f17 100644 --- a/plain-code/plain/code/oxc.py +++ b/plain-code/plain/code/oxc.py @@ -192,7 +192,16 @@ def download(self, version: str = "") -> str: dst.write(extracted.read()) os.chmod(tmp_path, 0o755) - os.replace(tmp_path, binary_path) + try: + os.replace(tmp_path, binary_path) + except PermissionError: + # Windows raises this if another process has binary_path open + # (e.g. another checkout sharing this machine-wide cache is + # currently running it). If it's already there, another + # process finished installing this exact version — nothing + # left to do. + if not binary_path.exists(): + raise finally: tmp_path.unlink(missing_ok=True) diff --git a/plain-tailwind/plain/tailwind/core.py b/plain-tailwind/plain/tailwind/core.py index 1958267a79..ab0af401cd 100644 --- a/plain-tailwind/plain/tailwind/core.py +++ b/plain-tailwind/plain/tailwind/core.py @@ -170,7 +170,16 @@ def download(self, version: str = "") -> str: binary_path = self.binary_path(version) binary_path.parent.mkdir(parents=True, exist_ok=True) - os.replace(tmp_path, binary_path) + try: + os.replace(tmp_path, binary_path) + except PermissionError: + # Windows raises this if another process has binary_path open + # (e.g. `plain tailwind build --watch` in a different checkout + # sharing this machine-wide cache). If it's already there, + # another process finished installing this exact version — + # nothing left to do. + if not binary_path.exists(): + raise finally: tmp_path.unlink(missing_ok=True)