diff --git a/varats-core/varats/provider/patch/patch_provider.py b/varats-core/varats/provider/patch/patch_provider.py index b370df208..d466a629b 100644 --- a/varats-core/varats/provider/patch/patch_provider.py +++ b/varats-core/varats/provider/patch/patch_provider.py @@ -18,6 +18,7 @@ from varats.project.project_util import get_local_project_git_path from varats.provider.provider import Provider, ProviderType +from varats.utils.filesystem_util import lock_file from varats.utils.git_commands import pull_current_branch, fetch_repository from varats.utils.git_util import ( CommitHash, @@ -237,12 +238,10 @@ class PatchProvider(Provider): def __init__(self, project: tp.Type[Project]): super().__init__(project) - # BB only performs a fetch so our repo might be out of date - pull_current_branch(self._get_patches_repository_path()) + self._update_local_patches_repo() + repo_path = self._get_patches_repository_path() - patches_project_dir = Path( - self._get_patches_repository_path() / self.project.NAME - ) + patches_project_dir = repo_path / self.project.NAME if not patches_project_dir.is_dir(): warnings.warn( @@ -316,6 +315,12 @@ def create_default_provider( @classmethod def _get_patches_repository_path(cls) -> Path: - cls.patches_source.fetch() - return Path(target_prefix()) / cls.patches_source.local + + @classmethod + def _update_local_patches_repo(cls): + lock_path = Path(target_prefix()) / "patch_provider.lock" + + with lock_file(lock_path): + cls.patches_source.fetch() + pull_current_branch(cls._get_patches_repository_path()) diff --git a/varats-core/varats/utils/filesystem_util.py b/varats-core/varats/utils/filesystem_util.py index 6f71f01d9..bc44c3265 100644 --- a/varats-core/varats/utils/filesystem_util.py +++ b/varats-core/varats/utils/filesystem_util.py @@ -1,6 +1,8 @@ """Utility functions for handling filesystem related tasks.""" - +import fcntl +import os.path import typing as tp +from contextlib import contextmanager from pathlib import Path @@ -13,3 +15,15 @@ def __init__(self, folder: tp.Union[Path, str]) -> None: f"Folder: '{str(folder)}' should be created " "but was already present." ) + + +@contextmanager +def lock_file(lock_path: Path, lock_mode: int = fcntl.LOCK_EX) -> tp.Generator: + open_mode = os.O_RDWR | os.O_CREAT | os.O_TRUNC + lock_fd = os.open(lock_path, open_mode) + try: + fcntl.flock(lock_fd, lock_mode) + yield + finally: + fcntl.flock(lock_fd, fcntl.LOCK_UN) + os.close(lock_fd)