Skip to content

Commit 40031c3

Browse files
authored
Merge pull request #169 from shanejbrown/main
Convert fcntl to portalocker to be windows compatible
2 parents c8729c2 + 2ac1d2b commit 40031c3

File tree

3 files changed

+27
-40
lines changed

3 files changed

+27
-40
lines changed

buildrunner/utils.py

Lines changed: 23 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88

99
from collections import OrderedDict
1010
from datetime import datetime
11-
import fcntl
1211
import io
1312
import logging
1413
import os
1514
import re
1615
import sys
17-
import time
1816
import uuid
17+
import portalocker
18+
import timeout_decorator
1919
import yaml.resolver
2020
import yaml.scanner
2121
import glob
@@ -213,46 +213,30 @@ def _acquire_flock_open(
213213
:param exclusive: config exclusive lock (True) or shared lock (False), defaults to True
214214
:return: opened file object if successful else None
215215
"""
216+
217+
@timeout_decorator.timeout(
218+
seconds=timeout_seconds, timeout_exception=FailureToAcquireLockException
219+
)
220+
def get_lock(file_obj: io.IOBase):
221+
flags = (
222+
portalocker.LockFlags.EXCLUSIVE
223+
if exclusive
224+
else portalocker.LockFlags.SHARED
225+
)
226+
portalocker.lock(
227+
file_obj,
228+
flags,
229+
)
230+
return file_obj
231+
216232
# pylint: disable=unspecified-encoding,consider-using-with
217233
file_obj = open(lock_file, mode)
218-
pid = os.getpid()
219234
lock_file_obj = None
220-
retry_sleep_seconds = 0.5
221-
222-
start_time = current_time = time.time()
223-
duration_seconds = current_time - start_time
224-
225-
while duration_seconds < timeout_seconds:
226-
try:
227-
# The LOCK_NB means non-blocking
228-
# More information here:
229-
# https://docs.python.org/3/library/fcntl.html#fcntl.flock
230-
if exclusive:
231-
# Obtain an exclusive lock, blocks shared (read) locks
232-
fcntl.flock(file_obj, fcntl.LOCK_EX | fcntl.LOCK_NB)
233-
else:
234-
# Allow multiple people to read from the file at the same time
235-
# If another instance adds an exclusive lock in the save method below,
236-
# this will block until the lock is released
237-
fcntl.flock(file_obj, fcntl.LOCK_SH | fcntl.LOCK_NB)
238-
except (IOError, OSError):
239-
# Limit the amount of logs written while waiting for the file lock
240-
num_seconds_between_log_writes = 10
241-
if (
242-
0
243-
<= (duration_seconds % num_seconds_between_log_writes)
244-
<= retry_sleep_seconds
245-
):
246-
logger.info(
247-
f"PID:{pid} waiting for file lock on {lock_file} after {duration_seconds} seconds"
248-
)
249-
else:
250-
lock_file_obj = file_obj
251-
break
252-
time.sleep(retry_sleep_seconds)
253-
duration_seconds = time.time() - start_time
235+
pid = os.getpid()
254236

255-
if lock_file_obj is None:
237+
try:
238+
lock_file_obj = get_lock(file_obj)
239+
except FailureToAcquireLockException:
256240
file_obj.close()
257241
raise FailureToAcquireLockException(
258242
f"PID:{pid} failed to acquire file lock for {lock_file} after timeout of {timeout_seconds} seconds"
@@ -322,6 +306,6 @@ def release_flock(
322306
"""
323307
if lock_file_obj is None:
324308
return
325-
fcntl.flock(lock_file_obj, fcntl.LOCK_UN)
309+
portalocker.unlock(lock_file_obj)
326310
lock_file_obj.close()
327311
logger.write(f"PID:{os.getpid()} released and closed file {lock_file_obj}")

requirements.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ python-on-whales>=0.70.1
1414
pydantic>=2.4.2
1515
retry2>=0.9.5
1616
colorlog>=6.8.0
17-
rich>=13
17+
rich>=13
18+
portalocker>=2.10.1

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ paramiko==3.2.0
7575
# fabric
7676
pkginfo==1.9.6
7777
# via twine
78+
portalocker==2.10.1
79+
# via -r requirements.in
7880
pycparser==2.21
7981
# via cffi
8082
pydantic==2.4.2

0 commit comments

Comments
 (0)