Skip to content

Commit

Permalink
fetch_refspecs: drop to dulwich if cred-helper is set (#189)
Browse files Browse the repository at this point in the history
  • Loading branch information
skshetry authored Feb 16, 2023
1 parent 82d0079 commit a52800e
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 21 deletions.
40 changes: 35 additions & 5 deletions src/scmrepo/git/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
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 Dict, Iterable, Optional, Tuple, Type, Union
from typing import TYPE_CHECKING, Callable, Dict, Iterable, Optional, Tuple, Type, Union

from funcy import cached_property, first
from pathspec.patterns import GitWildMatchPattern
Expand All @@ -16,12 +17,15 @@
from scmrepo.exceptions import FileNotInRepoError, GitHookAlreadyExists, RevError
from scmrepo.utils import relpath

from .backend.base import BaseGitBackend, NoGitBackendError
from .backend.base import BaseGitBackend, NoGitBackendError, SyncStatus
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]
Expand Down Expand Up @@ -310,6 +314,35 @@ 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")
Expand Down Expand Up @@ -337,9 +370,6 @@ def add_commit(
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=["pygit2", "dulwich"]
)
_stash_iter = partialmethod(_backend_func, "_stash_iter")
_stash_push = partialmethod(_backend_func, "_stash_push")
_stash_apply = partialmethod(_backend_func, "_stash_apply")
Expand Down
2 changes: 1 addition & 1 deletion src/scmrepo/git/backend/dulwich/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from dulwich.client import Urllib3HttpGitClient
from dulwich.config import StackedConfig

from .credentials import CredentialNotFoundError, get_credentials_from_helper
from scmrepo.git.credentials import CredentialNotFoundError, get_credentials_from_helper


class GitCredentialsHTTPClient(Urllib3HttpGitClient): # pylint: disable=abstract-method
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,7 @@ def erase(self, *args, **kwargs):
raise NotImplementedError


def get_credentials_from_helper(base_url: str, config) -> Tuple[bytes, bytes]:
"""Retrieves credentials for the given url from git credential helpers"""
def get_matching_helper_commands(base_url: str, config):
if isinstance(config, StackedConfig):
backends = config.backends
else:
Expand All @@ -175,19 +174,22 @@ def get_credentials_from_helper(base_url: str, config) -> Tuple[bytes, bytes]:
except KeyError:
# no helper configured
continue
yield command.decode(conf.encoding or sys.getdefaultencoding())

helper = CredentialHelper(
command.decode(conf.encoding or sys.getdefaultencoding())
)
parsed = urlparse(base_url)
try:
return helper.get(
protocol=parsed.scheme,
hostname=parsed.hostname,
port=parsed.port,
username=parsed.username,
)
except CredentialNotFoundError:
continue

def get_credentials_from_helper(base_url: str, config) -> Tuple[bytes, bytes]:
"""Retrieves credentials for the given url from git credential helpers"""

for command in get_matching_helper_commands(base_url, config):
helper = CredentialHelper(command)
parsed = urlparse(base_url)
try:
return helper.get(
protocol=parsed.scheme,
hostname=parsed.hostname,
port=parsed.port,
username=parsed.username,
)
except CredentialNotFoundError:
continue
raise CredentialNotFoundError

0 comments on commit a52800e

Please sign in to comment.