diff --git a/backend/infrahub/git/base.py b/backend/infrahub/git/base.py index 38ac5b4c3c..0792118158 100644 --- a/backend/infrahub/git/base.py +++ b/backend/infrahub/git/base.py @@ -15,6 +15,7 @@ from pydantic import BaseModel, ConfigDict, Field from pydantic import ValidationError as PydanticValidationError +from infrahub import lock from infrahub.core.branch import Branch from infrahub.core.constants import InfrahubKind from infrahub.core.registry import registry @@ -28,6 +29,7 @@ from infrahub.git.constants import BRANCHES_DIRECTORY_NAME, COMMITS_DIRECTORY_NAME, TEMPORARY_DIRECTORY_NAME from infrahub.git.directory import get_repositories_directory, initialize_repositories_directory from infrahub.git.worktree import Worktree +from infrahub.lock import LOCAL_REPO_LOCK from infrahub.log import get_logger from infrahub.services import InfrahubServices # noqa: TCH001 @@ -306,6 +308,16 @@ def validate_local_directories(self) -> bool: async def create_locally( self, checkout_ref: str | None = None, infrahub_branch_name: str | None = None, update_commit_value: bool = True + ) -> bool: + async with lock.registry.get(name=LOCAL_REPO_LOCK, namespace=self.name, local=True): + return await self._create_locally( + checkout_ref=checkout_ref, + infrahub_branch_name=infrahub_branch_name, + update_commit_value=update_commit_value, + ) + + async def _create_locally( + self, checkout_ref: str | None = None, infrahub_branch_name: str | None = None, update_commit_value: bool = True ) -> bool: """Ensure the required directory already exist in the filesystem or create them if needed. @@ -313,6 +325,7 @@ async def create_locally( True if the directory has been created, False if the directory was already present. """ + initialize_repositories_directory() if not self.location: @@ -653,6 +666,11 @@ async def validate_remote_branch(self, branch_name: str) -> bool: async def pull(self, branch_name: str) -> Union[bool, str]: """Pull the latest update from the remote repository on a given branch.""" + async with lock.registry.get(name=LOCAL_REPO_LOCK, namespace=self.name, local=True): + return await self._pull_unsafe(branch_name=branch_name) + + async def _pull_unsafe(self, branch_name: str) -> Union[bool, str]: + """Pull the latest update from the remote repository on a given branch.""" if not self.has_origin: return False diff --git a/backend/infrahub/git/integrator.py b/backend/infrahub/git/integrator.py index 1be534de32..7276ae6fb4 100644 --- a/backend/infrahub/git/integrator.py +++ b/backend/infrahub/git/integrator.py @@ -139,8 +139,9 @@ async def init(cls, commit: str | None = None, service: InfrahubServices | None await self.ensure_location_is_defined() await self.create_locally(infrahub_branch_name=self.infrahub_branch_name, update_commit_value=False) service.log.info(f"Initialized the local directory for {self.name} because it was missing.") - if commit: - self.get_commit_worktree(commit=commit) + + if commit: + self.get_commit_worktree(commit=commit) service.log.debug( f"Initiated the object on an existing directory for {self.name}", diff --git a/backend/infrahub/git/repository.py b/backend/infrahub/git/repository.py index 15be219207..f67ae38402 100644 --- a/backend/infrahub/git/repository.py +++ b/backend/infrahub/git/repository.py @@ -6,9 +6,11 @@ from infrahub_sdk.exceptions import GraphQLError from pydantic import Field +from infrahub import lock from infrahub.core.constants import InfrahubKind, RepositoryInternalStatus from infrahub.exceptions import RepositoryError from infrahub.git.integrator import InfrahubRepositoryIntegrator +from infrahub.lock import LOCAL_REPO_LOCK from infrahub.log import get_logger from infrahub.services import InfrahubServices @@ -94,6 +96,10 @@ async def create_branch_in_git( return True async def sync(self, staging_branch: str | None = None) -> None: + async with lock.registry.get(name=LOCAL_REPO_LOCK, namespace=self.name, local=True): + return await self._sync_unsafe(staging_branch=staging_branch) + + async def _sync_unsafe(self, staging_branch: str | None = None) -> None: """Synchronize the repository with its remote origin and with the database. By default the sync will focus only on the branches pulled from origin that have some differences with the local one. @@ -275,6 +281,10 @@ def get_commit_value(self, branch_name: str, remote: bool = False) -> str: return str(commit) async def sync_from_remote(self, commit: str | None = None) -> None: + async with lock.registry.get(name=LOCAL_REPO_LOCK, namespace=self.name, local=True): + return await self._sync_from_remote_unsafe(commit=commit) + + async def _sync_from_remote_unsafe(self, commit: str | None = None) -> None: if not commit: commit = self.get_commit_value(branch_name=self.ref, remote=True) local_branches = self.get_branches_from_local() diff --git a/backend/infrahub/lock.py b/backend/infrahub/lock.py index ae1237bf13..1773f22794 100644 --- a/backend/infrahub/lock.py +++ b/backend/infrahub/lock.py @@ -39,6 +39,7 @@ ) LOCAL_SCHEMA_LOCK = "local.schema" +LOCAL_REPO_LOCK = "local.repository" GLOBAL_INIT_LOCK = "global.init" GLOBAL_SCHEMA_LOCK = "global.schema" GLOBAL_GRAPH_LOCK = "global.graph"