wrap: Lock subproject directory when downloading wraps

To avoid raceconditions, where one instance of meson currently downloads
a subproject defined in a wrapfile, while another either
  a. starts the download itself too
  b. attemts to evaluate the partially downloaded subproject
wraplock introduces a lockfile, which should prevent simultaneous access
of subprojects by wrap between different instances of meson.
This commit is contained in:
Florian "sp1rit"​ authored and Jussi Pakkanen committed 2025-06-03 15:43:58 +03:00
1 parent 4a14c4faf9
commit 98b1980b53
4 files changed
+17 -4

No files matched your search

+1
View File
@@ -22,6 +22,7 @@ __pycache__
*~
*.swp
packagecache
.wraplock
/MANIFEST
/build
/dist
+14 -2
View File
@@ -30,7 +30,10 @@ from functools import lru_cache
from . import WrapMode
from .. import coredata
from ..mesonlib import quiet_git, GIT, ProgressBar, MesonException, windows_proof_rmtree, Popen_safe
from ..mesonlib import (
DirectoryLock, DirectoryLockAction, quiet_git, GIT, ProgressBar, MesonException,
windows_proof_rmtree, Popen_safe
)
from ..interpreterbase import FeatureNew
from ..interpreterbase import SubProject
from .. import mesonlib
@@ -449,7 +452,7 @@ class Resolver:
return wrap_name
return None
def resolve(self, packagename: str, force_method: T.Optional[Method] = None) -> T.Tuple[str, Method]:
def _resolve(self, packagename: str, force_method: T.Optional[Method] = None) -> T.Tuple[str, Method]:
wrap = self.wraps.get(packagename)
if wrap is None:
wrap = self.get_from_wrapdb(packagename)
@@ -547,6 +550,15 @@ class Resolver:
self.wrap.update_hash_cache(self.dirname)
return rel_path, method
def resolve(self, packagename: str, force_method: T.Optional[Method] = None) -> T.Tuple[str, Method]:
try:
with DirectoryLock(self.subdir_root, '.wraplock',
DirectoryLockAction.WAIT,
'Failed to lock subprojects directory'):
return self._resolve(packagename, force_method)
except FileNotFoundError:
raise WrapNotFoundException('Attempted to resolve subproject without subprojects directory present.')
def check_can_download(self) -> None:
# Don't download subproject data based on wrap file if requested.
# Git submodules are ok (see above)!
@@ -1,7 +1,7 @@
{
"stdout": [
{
"line": "test cases/failing/33 non-root subproject/some/meson.build:1:0: ERROR: Neither a subproject directory nor a someproj.wrap file was found."
"line": "test cases/failing/33 non-root subproject/some/meson.build:1:0: ERROR: Attempted to resolve subproject without subprojects directory present."
}
]
}
@@ -1,7 +1,7 @@
{
"stdout": [
{
"line": "test cases/failing/73 subproj dependency not-found and required/meson.build:2:10: ERROR: Neither a subproject directory nor a missing.wrap file was found."
"line": "test cases/failing/73 subproj dependency not-found and required/meson.build:2:10: ERROR: Attempted to resolve subproject without subprojects directory present."
}
]
}