diff options
| author | Florian "sp1rit" <sp1rit@disroot.org> | 2024-11-01 12:37:29 +0100 |
|---|---|---|
| committer | Jussi Pakkanen <jussi.pakkanen@mailbox.org> | 2025-06-03 15:43:58 +0300 |
| commit | 4a14c4faf93361832ecb0134e1c0f58a239b4f15 (patch) | |
| tree | e24df2730fea2c3d32d299bdccb3b8a6a6075975 | |
| parent | 960509811e3999f83c67607ce2a5a76e2a7bd36e (diff) | |
| download | meson-4a14c4faf93361832ecb0134e1c0f58a239b4f15.tar.gz | |
utils: Replace BuildDirLock with generic DirectoryLock
DirectoryLock provides a generic locking implementation the replaces the
previously used BuildDirLock.
| -rw-r--r-- | mesonbuild/msetup.py | 4 | ||||
| -rw-r--r-- | mesonbuild/utils/platform.py | 22 | ||||
| -rw-r--r-- | mesonbuild/utils/posix.py | 26 | ||||
| -rw-r--r-- | mesonbuild/utils/win32.py | 24 | ||||
| -rw-r--r-- | unittests/allplatformstests.py | 7 |
5 files changed, 56 insertions, 27 deletions
diff --git a/mesonbuild/msetup.py b/mesonbuild/msetup.py index d4e745468..32344cae6 100644 --- a/mesonbuild/msetup.py +++ b/mesonbuild/msetup.py @@ -188,7 +188,9 @@ class MesonApp: mlog.set_timestamp_start(time.monotonic()) if self.options.clearcache: env.coredata.clear_cache() - with mesonlib.BuildDirLock(self.build_dir): + with mesonlib.DirectoryLock(self.build_dir, 'meson-private/meson.lock', + mesonlib.DirectoryLockAction.FAIL, + 'Some other Meson process is already using this build directory. Exiting.'): return self._generate(env, capture, vslite_ctx) def check_unused_options(self, coredata: 'coredata.CoreData', cmd_line_options: T.Any, all_subprojects: T.Mapping[str, object]) -> None: diff --git a/mesonbuild/utils/platform.py b/mesonbuild/utils/platform.py index 8e762b63f..8fdfee6e5 100644 --- a/mesonbuild/utils/platform.py +++ b/mesonbuild/utils/platform.py @@ -6,22 +6,30 @@ from __future__ import annotations """base classes providing no-op functionality..""" +import enum import os import typing as T from .. import mlog -__all__ = ['BuildDirLock'] +__all__ = ['DirectoryLock', 'DirectoryLockAction', 'DirectoryLockBase'] -# This needs to be inherited by the specific implementations to make type -# checking happy -class BuildDirLock: +class DirectoryLockAction(enum.Enum): + IGNORE = 0 + WAIT = 1 + FAIL = 2 - def __init__(self, builddir: str) -> None: - self.lockfilename = os.path.join(builddir, 'meson-private/meson.lock') +class DirectoryLockBase: + def __init__(self, directory: str, lockfile: str, action: DirectoryLockAction, err: str) -> None: + self.action = action + self.err = err + self.lockpath = os.path.join(directory, lockfile) def __enter__(self) -> None: - mlog.debug('Calling the no-op version of BuildDirLock') + mlog.debug('Calling the no-op version of DirectoryLock') def __exit__(self, *args: T.Any) -> None: pass + +class DirectoryLock(DirectoryLockBase): + pass diff --git a/mesonbuild/utils/posix.py b/mesonbuild/utils/posix.py index e8387ba17..a601dee46 100644 --- a/mesonbuild/utils/posix.py +++ b/mesonbuild/utils/posix.py @@ -10,23 +10,33 @@ import fcntl import typing as T from .core import MesonException -from .platform import BuildDirLock as BuildDirLockBase +from .platform import DirectoryLockBase, DirectoryLockAction -__all__ = ['BuildDirLock'] +__all__ = ['DirectoryLock', 'DirectoryLockAction'] -class BuildDirLock(BuildDirLockBase): +class DirectoryLock(DirectoryLockBase): def __enter__(self) -> None: - self.lockfile = open(self.lockfilename, 'w', encoding='utf-8') + self.lockfile = open(self.lockpath, 'w+', encoding='utf-8') try: - fcntl.flock(self.lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB) - except (BlockingIOError, PermissionError): + flags = fcntl.LOCK_EX + if self.action != DirectoryLockAction.WAIT: + flags = flags | fcntl.LOCK_NB + fcntl.flock(self.lockfile, flags) + except BlockingIOError: self.lockfile.close() - raise MesonException('Some other Meson process is already using this build directory. Exiting.') + if self.action == DirectoryLockAction.IGNORE: + return + raise MesonException(self.err) + except PermissionError: + self.lockfile.close() + raise MesonException(self.err) except OSError as e: self.lockfile.close() - raise MesonException(f'Failed to lock the build directory: {e.strerror}') + raise MesonException(f'Failed to lock directory {self.lockpath}: {e.strerror}') def __exit__(self, *args: T.Any) -> None: + if self.lockfile is None or self.lockfile.closed: + return fcntl.flock(self.lockfile, fcntl.LOCK_UN) self.lockfile.close() diff --git a/mesonbuild/utils/win32.py b/mesonbuild/utils/win32.py index 4fcb8ed83..22aea8680 100644 --- a/mesonbuild/utils/win32.py +++ b/mesonbuild/utils/win32.py @@ -10,20 +10,30 @@ import msvcrt import typing as T from .core import MesonException -from .platform import BuildDirLock as BuildDirLockBase +from .platform import DirectoryLockBase, DirectoryLockAction -__all__ = ['BuildDirLock'] +__all__ = ['DirectoryLock', 'DirectoryLockAction'] -class BuildDirLock(BuildDirLockBase): +class DirectoryLock(DirectoryLockBase): def __enter__(self) -> None: - self.lockfile = open(self.lockfilename, 'w', encoding='utf-8') + self.lockfile = open(self.lockpath, 'w+', encoding='utf-8') try: - msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_NBLCK, 1) - except (BlockingIOError, PermissionError): + mode = msvcrt.LK_LOCK + if self.action != DirectoryLockAction.WAIT: + mode = msvcrt.LK_NBLCK + msvcrt.locking(self.lockfile.fileno(), mode, 1) + except BlockingIOError: self.lockfile.close() - raise MesonException('Some other Meson process is already using this build directory. Exiting.') + if self.action == DirectoryLockAction.IGNORE: + return + raise MesonException(self.err) + except PermissionError: + self.lockfile.close() + raise MesonException(self.err) def __exit__(self, *args: T.Any) -> None: + if self.lockfile is None or self.lockfile.closed: + return msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_UNLCK, 1) self.lockfile.close() diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index fa6f11965..536fb612a 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -29,7 +29,7 @@ import mesonbuild.coredata import mesonbuild.machinefile import mesonbuild.modules.gnome from mesonbuild.mesonlib import ( - BuildDirLock, MachineChoice, is_windows, is_osx, is_cygwin, is_dragonflybsd, + DirectoryLock, DirectoryLockAction, MachineChoice, is_windows, is_osx, is_cygwin, is_dragonflybsd, is_sunos, windows_proof_rmtree, python_command, version_compare, split_args, quote_arg, relpath, is_linux, git, search_version, do_conf_file, do_conf_str, default_prefix, MesonException, EnvironmentException, @@ -2499,10 +2499,9 @@ class AllPlatformTests(BasePlatformTests): def test_flock(self): exception_raised = False with tempfile.TemporaryDirectory() as tdir: - os.mkdir(os.path.join(tdir, 'meson-private')) - with BuildDirLock(tdir): + with DirectoryLock(tdir, 'lock', DirectoryLockAction.FAIL, 'failed to lock directory'): try: - with BuildDirLock(tdir): + with DirectoryLock(tdir, 'lock', DirectoryLockAction.FAIL, 'expected failure'): pass except MesonException: exception_raised = True |
