# HG changeset patch # User Georges Racinet <georges.racinet@octobus.net> # Date 1695549262 -7200 # Sun Sep 24 11:54:22 2023 +0200 # Node ID ff9416677544542275ac771acbdbd43ddd01647a # Parent 14ed25522afed680513eaf71c5c7e36f1b404e84 RepositoryService: move repo creation to servicer base class This is not exactly what was suggested in the removed todo comment, because it contains context-based error treatment and uses repository loading methods, but still provides clean mutualization, that could for instance also been used in `MercurialRepositoryService`. diff --git a/hgitaly/service/repository.py b/hgitaly/service/repository.py --- a/hgitaly/service/repository.py +++ b/hgitaly/service/repository.py @@ -20,7 +20,6 @@ archival, pycompat, scmutil, - hg, node, ) from mercurial.commands import ( @@ -47,7 +46,6 @@ iter_gitlab_branches, ) from ..errors import ( - ServiceError, not_implemented, ) from ..gitlab_ref import ( @@ -125,9 +123,6 @@ ApplyGitattributesResponse, ) from ..stub.repository_pb2_grpc import RepositoryServiceServicer -from ..stub.shared_pb2 import ( - Repository, -) base_logger = logging.getLogger(__name__) @@ -145,10 +140,6 @@ """ -class RepositoryCreationError(ServiceError): - """Specific exception for creation problems.""" - - class RepositoryServicer(RepositoryServiceServicer, HGitalyServicer): """RepositoryServiceService implementation. """ @@ -669,14 +660,10 @@ sub-request contains repository+data and subsequent sub-requests contains only data (i.e. the actual bundle sent in parts). """ - def init_repo(req, context): - # TODO should move to hgitaly.repository - self.hg_init_repository(req.repository, context) - return self.load_repo(req.repository, context) - with streaming_request_tempfile_extract( request, context, - first_request_handler=init_repo + first_request_handler=lambda rq, c: self.create_and_load_repo( + rq.repository, c), ) as (repo, tmpf): try: unbundle(repo, tmpf.name) @@ -722,39 +709,6 @@ context.abort(StatusCode.INTERNAL, "remove all: %s" % exc) return RemoveAllResponse() - def hg_init_repository(self, repository: Repository, context): - """Initialize a mercurial repository from a request object. - - :return: ``None``: the resulting repository has to be loaded in the - standard way, using its path. - :raises RepositoryCreationError: and updates context with error - code and details. - """ - logger = LoggerAdapter(base_logger, context) - try: - repo_path = self.repo_disk_path(repository, context) - except KeyError: - msg = "no such storage: %r" % repository.storage_name - context.set_details(msg) - logger.error(msg) - context.set_code(StatusCode.INVALID_ARGUMENT) - raise RepositoryCreationError(repository) - - if os.path.lexists(repo_path): - msg = ("creating repository: repository exists already") - context.set_details(msg) - context.set_code(StatusCode.ALREADY_EXISTS) - raise RepositoryCreationError(repository) - - try: - logger.info("Creating repository at %r", repo_path) - hg.peer(self.ui, opts={}, path=repo_path, create=True) - except OSError as exc: - context.set_code(StatusCode.INTERNAL) - context.set_details("hg_init_repository(%r): %r" % (repo_path, - exc)) - raise RepositoryCreationError(repository) - def render_git_grep_matches(buf, ref, path, enum_lines): """Render a slice of lines as git grep does. diff --git a/hgitaly/servicer.py b/hgitaly/servicer.py --- a/hgitaly/servicer.py +++ b/hgitaly/servicer.py @@ -20,6 +20,8 @@ ) from mercurial.repoview import _filteredrepotypes +from .errors import ServiceError +from .logging import LoggerAdapter from .workdir import working_directory from .stub.shared_pb2 import ( Repository, @@ -58,6 +60,10 @@ return rpath +class RepositoryCreationError(ServiceError): + """Specific exception for creation problems.""" + + class HGitalyServicer: """Common features of all HGitaly services. @@ -138,6 +144,14 @@ context.abort(self.STATUS_CODE_REPO_NOT_FOUND, exc_args[1]) + def create_and_load_repo(self, repository: Repository, context): + """Create the repository and load it. + + :raises RepositoryCreationError: + """ + self.hg_init_repository(repository, context) + return self.load_repo_inner(repository, context) + def load_repo_inner(self, repository: Repository, context): """Load the repository from storage name and relative path @@ -273,3 +287,36 @@ with working_directory(tmp / 'workdirs' / rpath, repo, changeset=changeset) as wd: yield wd + + def hg_init_repository(self, repository: Repository, context): + """Initialize a mercurial repository from a request object. + + :return: ``None``: the resulting repository has to be loaded in the + standard way, using its path. + :raises RepositoryCreationError: and updates context with error + code and details. + """ + corr_logger = LoggerAdapter(logger, context) + try: + repo_path = self.repo_disk_path(repository, context) + except KeyError: + msg = "no such storage: %r" % repository.storage_name + context.set_details(msg) + corr_logger.error(msg) + context.set_code(StatusCode.INVALID_ARGUMENT) + raise RepositoryCreationError(repository) + + if os.path.lexists(repo_path): + msg = ("creating repository: repository exists already") + context.set_details(msg) + context.set_code(StatusCode.ALREADY_EXISTS) + raise RepositoryCreationError(repository) + + try: + corr_logger.info("Creating repository at %r", repo_path) + hg.peer(self.ui, opts={}, path=repo_path, create=True) + except OSError as exc: + context.set_code(StatusCode.INTERNAL) + context.set_details("hg_init_repository(%r): %r" % (repo_path, + exc)) + raise RepositoryCreationError(repository)