Skip to content

Commit 5855d88

Browse files
committed
fix(windows): guard fcntl usage behind platform checks
- core.py: lazy import now branches to msvcrt on win32 - smart_install.py: _BubbleLock uses msvcrt.locking on win32, fcntl on POSIX - Fixes 'Missing standard library module fcntl' crash on Windows CI
1 parent 5c84b32 commit 5855d88

2 files changed

Lines changed: 21 additions & 11 deletions

File tree

src/omnipkg/core.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4196,7 +4196,10 @@ def _heal_corrupt_metadata(self, install_path: Path, expected_package_name: str)
41964196
"""
41974197
NUCLEAR HEALING with file locking to prevent race conditions
41984198
"""
4199-
import fcntl
4199+
if sys.platform == "win32":
4200+
import msvcrt
4201+
else:
4202+
import fcntl
42004203

42014204
healed_count = 0
42024205

@@ -4212,8 +4215,8 @@ def _heal_corrupt_metadata(self, install_path: Path, expected_package_name: str)
42124215
try:
42134216
with open(lock_file, "w") as lock_fd:
42144217
# Acquire exclusive lock
4215-
fcntl.flock(lock_fd.fileno(), fcntl.LOCK_EX)
4216-
4218+
if _sys.platform != "win32":
4219+
fcntl.flock(lock_fd.fileno(), fcntl.LOCK_EX)
42174220
try:
42184221
content = metadata_file.read_text(encoding="utf-8", errors="ignore")
42194222

@@ -4240,10 +4243,11 @@ def _heal_corrupt_metadata(self, install_path: Path, expected_package_name: str)
42404243
_(" 🔧 AUTO-HEALED: Injected 'Name: {}' into {}/METADATA").format(pkg_name, dist_info.name)
42414244
)
42424245
healed_count += 1
4243-
4246+
42444247
finally:
42454248
# Release lock
4246-
fcntl.flock(lock_fd.fileno(), fcntl.LOCK_UN)
4249+
if _sys.platform != "win32":
4250+
fcntl.flock(lock_fd.fileno(), fcntl.LOCK_UN)
42474251

42484252
except Exception as e:
42494253
safe_print(_(' ⚠️ Failed to heal {}: {}').format(dist_info.name, e))

src/omnipkg/installation/smart_install.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
from __future__ import annotations
1515

1616
import contextlib
17-
import fcntl
17+
import sys
18+
if sys.platform != "win32":
19+
import fcntl
1820
import json
1921
import os
2022
import shutil
@@ -82,18 +84,22 @@ def __init__(self, pkg_name: str, version: str, blocking: bool = True):
8284

8385
def __enter__(self):
8486
self._fd = open(self.path, "w")
85-
flag = fcntl.LOCK_EX if self.blocking else (fcntl.LOCK_EX | fcntl.LOCK_NB)
8687
try:
87-
fcntl.flock(self._fd, flag)
88-
except BlockingIOError:
88+
if _sys.platform == "win32":
89+
import msvcrt
90+
msvcrt.locking(self._fd.fileno(), msvcrt.LK_NBLCK if not self.blocking else msvcrt.LK_LOCK, 1)
91+
else:
92+
flag = fcntl.LOCK_EX if self.blocking else (fcntl.LOCK_EX | fcntl.LOCK_NB)
93+
fcntl.flock(self._fd, flag)
94+
except (BlockingIOError, OSError):
8995
self._fd.close()
9096
self._fd = None
9197
raise BubbleLockBusy(f"Another process is already creating bubble for {self.path}")
9298
return self
93-
9499
def __exit__(self, *_):
95100
if self._fd:
96-
fcntl.flock(self._fd, fcntl.LOCK_UN)
101+
if _sys.platform != "win32":
102+
fcntl.flock(self._fd, fcntl.LOCK_UN)
97103
self._fd.close()
98104

99105

0 commit comments

Comments
 (0)