From b0467bab4730a0198edce6a9b47c70bccbff6eb8 Mon Sep 17 00:00:00 2001 From: Ruslan Kuprieiev Date: Fri, 17 Mar 2023 02:27:08 +0200 Subject: [PATCH] git: prefer gitpython for auth ops clone/push/pull/fetch/push_refspecs/fetch_refspecs all rely on auth heavily and git CLI, unfortunately, handles it the best across the board. Note that push/fetch_refspecs are not implemented in gitpython backend yet, so this won't work for them until those are implemented. Fixes #208 --- src/scmrepo/git/__init__.py | 57 +++++++++++-------------------------- 1 file changed, 16 insertions(+), 41 deletions(-) diff --git a/src/scmrepo/git/__init__.py b/src/scmrepo/git/__init__.py index bbdb9c81..1db24cfb 100644 --- a/src/scmrepo/git/__init__.py +++ b/src/scmrepo/git/__init__.py @@ -3,12 +3,11 @@ import logging import os import re -import typing from collections import OrderedDict from collections.abc import Mapping from contextlib import contextmanager from functools import partialmethod -from typing import TYPE_CHECKING, Callable, Dict, Iterable, Optional, Tuple, Type, Union +from typing import Dict, Iterable, Optional, Tuple, Type, Union from funcy import cached_property, first from git import GitCommandNotFound @@ -18,22 +17,21 @@ from scmrepo.exceptions import FileNotInRepoError, GitHookAlreadyExists, RevError from scmrepo.utils import relpath -from .backend.base import BaseGitBackend, NoGitBackendError, SyncStatus +from .backend.base import BaseGitBackend, NoGitBackendError from .backend.dulwich import DulwichBackend from .backend.gitpython import GitPythonBackend from .backend.pygit2 import Pygit2Backend from .stash import Stash -if TYPE_CHECKING: - from scmrepo.progress import GitProgressEvent - logger = logging.getLogger(__name__) BackendCls = Type[BaseGitBackend] - _LOW_PRIO_BACKENDS = ("gitpython",) +# NOTE: preferring gitpython because CLI git handles auth best +_AUTH_BACKENDS = ("gitpython", "dulwich", "pygit2") + _SKIPPABLE = (NotImplementedError, GitCommandNotFound) @@ -137,7 +135,8 @@ def clone( rev: Optional[str] = None, **kwargs, ): - for _, backend in GitBackends.DEFAULT.items(): + for name in _AUTH_BACKENDS: + backend = GitBackends.DEFAULT[name] try: backend.clone(url, to_path, **kwargs) repo = cls(to_path) @@ -317,42 +316,13 @@ def add_commit( self.add(paths) self.commit(msg=message) - _fetch_refspecs = partialmethod( - _backend_func, "fetch_refspecs", backends=["pygit2", "dulwich"] - ) - - def fetch_refspecs( - self, - url: str, - refspecs: Union[str, Iterable[str]], - force: bool = False, - on_diverged: Optional[Callable[[str, str], bool]] = None, - progress: Optional[Callable[["GitProgressEvent"], None]] = None, - **kwargs, - ) -> typing.Mapping[str, SyncStatus]: - from .credentials import get_matching_helper_commands - - if "dulwich" in kwargs.get("backends", self.backends.backends) and any( - get_matching_helper_commands(url, self.dulwich.repo.get_config_stack()) - ): - kwargs["backends"] = ["dulwich"] - - return self._fetch_refspecs( - url, - refspecs, - force=force, - on_diverged=on_diverged, - progress=progress, - **kwargs, - ) - is_ignored = partialmethod(_backend_func, "is_ignored") add = partialmethod(_backend_func, "add") commit = partialmethod(_backend_func, "commit") checkout = partialmethod(_backend_func, "checkout") - fetch = partialmethod(_backend_func, "fetch") - pull = partialmethod(_backend_func, "pull") - push = partialmethod(_backend_func, "push") + fetch = partialmethod(_backend_func, "fetch", backends=_AUTH_BACKENDS) + pull = partialmethod(_backend_func, "pull", backends=_AUTH_BACKENDS) + push = partialmethod(_backend_func, "push", backends=_AUTH_BACKENDS) branch = partialmethod(_backend_func, "branch") tag = partialmethod(_backend_func, "tag") untracked_files = partialmethod(_backend_func, "untracked_files") @@ -372,7 +342,12 @@ def fetch_refspecs( iter_refs = partialmethod(_backend_func, "iter_refs") iter_remote_refs = partialmethod(_backend_func, "iter_remote_refs") get_refs_containing = partialmethod(_backend_func, "get_refs_containing") - push_refspecs = partialmethod(_backend_func, "push_refspecs") + fetch_refspecs = partialmethod( + _backend_func, "fetch_refspecs", backends=_AUTH_BACKENDS + ) + push_refspecs = partialmethod( + _backend_func, "push_refspecs", backends=_AUTH_BACKENDS + ) _stash_iter = partialmethod(_backend_func, "_stash_iter") _stash_push = partialmethod(_backend_func, "_stash_push") _stash_apply = partialmethod(_backend_func, "_stash_apply")