Skip to content

Commit a52800e

Browse files
authored
fetch_refspecs: drop to dulwich if cred-helper is set (#189)
1 parent 82d0079 commit a52800e

File tree

3 files changed

+53
-21
lines changed

3 files changed

+53
-21
lines changed

src/scmrepo/git/__init__.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
import logging
44
import os
55
import re
6+
import typing
67
from collections import OrderedDict
78
from collections.abc import Mapping
89
from contextlib import contextmanager
910
from functools import partialmethod
10-
from typing import Dict, Iterable, Optional, Tuple, Type, Union
11+
from typing import TYPE_CHECKING, Callable, Dict, Iterable, Optional, Tuple, Type, Union
1112

1213
from funcy import cached_property, first
1314
from pathspec.patterns import GitWildMatchPattern
@@ -16,12 +17,15 @@
1617
from scmrepo.exceptions import FileNotInRepoError, GitHookAlreadyExists, RevError
1718
from scmrepo.utils import relpath
1819

19-
from .backend.base import BaseGitBackend, NoGitBackendError
20+
from .backend.base import BaseGitBackend, NoGitBackendError, SyncStatus
2021
from .backend.dulwich import DulwichBackend
2122
from .backend.gitpython import GitPythonBackend
2223
from .backend.pygit2 import Pygit2Backend
2324
from .stash import Stash
2425

26+
if TYPE_CHECKING:
27+
from scmrepo.progress import GitProgressEvent
28+
2529
logger = logging.getLogger(__name__)
2630

2731
BackendCls = Type[BaseGitBackend]
@@ -310,6 +314,35 @@ def add_commit(
310314
self.add(paths)
311315
self.commit(msg=message)
312316

317+
_fetch_refspecs = partialmethod(
318+
_backend_func, "fetch_refspecs", backends=["pygit2", "dulwich"]
319+
)
320+
321+
def fetch_refspecs(
322+
self,
323+
url: str,
324+
refspecs: Union[str, Iterable[str]],
325+
force: bool = False,
326+
on_diverged: Optional[Callable[[str, str], bool]] = None,
327+
progress: Optional[Callable[["GitProgressEvent"], None]] = None,
328+
**kwargs,
329+
) -> typing.Mapping[str, SyncStatus]:
330+
from .credentials import get_matching_helper_commands
331+
332+
if "dulwich" in kwargs.get("backends", self.backends.backends) and any(
333+
get_matching_helper_commands(url, self.dulwich.repo.get_config_stack())
334+
):
335+
kwargs["backends"] = ["dulwich"]
336+
337+
return self._fetch_refspecs(
338+
url,
339+
refspecs,
340+
force=force,
341+
on_diverged=on_diverged,
342+
progress=progress,
343+
**kwargs,
344+
)
345+
313346
is_ignored = partialmethod(_backend_func, "is_ignored")
314347
add = partialmethod(_backend_func, "add")
315348
commit = partialmethod(_backend_func, "commit")
@@ -337,9 +370,6 @@ def add_commit(
337370
iter_remote_refs = partialmethod(_backend_func, "iter_remote_refs")
338371
get_refs_containing = partialmethod(_backend_func, "get_refs_containing")
339372
push_refspecs = partialmethod(_backend_func, "push_refspecs")
340-
fetch_refspecs = partialmethod(
341-
_backend_func, "fetch_refspecs", backends=["pygit2", "dulwich"]
342-
)
343373
_stash_iter = partialmethod(_backend_func, "_stash_iter")
344374
_stash_push = partialmethod(_backend_func, "_stash_push")
345375
_stash_apply = partialmethod(_backend_func, "_stash_apply")

src/scmrepo/git/backend/dulwich/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from dulwich.client import Urllib3HttpGitClient
55
from dulwich.config import StackedConfig
66

7-
from .credentials import CredentialNotFoundError, get_credentials_from_helper
7+
from scmrepo.git.credentials import CredentialNotFoundError, get_credentials_from_helper
88

99

1010
class GitCredentialsHTTPClient(Urllib3HttpGitClient): # pylint: disable=abstract-method

src/scmrepo/git/backend/dulwich/credentials.py renamed to src/scmrepo/git/credentials.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,7 @@ def erase(self, *args, **kwargs):
159159
raise NotImplementedError
160160

161161

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

179-
helper = CredentialHelper(
180-
command.decode(conf.encoding or sys.getdefaultencoding())
181-
)
182-
parsed = urlparse(base_url)
183-
try:
184-
return helper.get(
185-
protocol=parsed.scheme,
186-
hostname=parsed.hostname,
187-
port=parsed.port,
188-
username=parsed.username,
189-
)
190-
except CredentialNotFoundError:
191-
continue
192179

180+
def get_credentials_from_helper(base_url: str, config) -> Tuple[bytes, bytes]:
181+
"""Retrieves credentials for the given url from git credential helpers"""
182+
183+
for command in get_matching_helper_commands(base_url, config):
184+
helper = CredentialHelper(command)
185+
parsed = urlparse(base_url)
186+
try:
187+
return helper.get(
188+
protocol=parsed.scheme,
189+
hostname=parsed.hostname,
190+
port=parsed.port,
191+
username=parsed.username,
192+
)
193+
except CredentialNotFoundError:
194+
continue
193195
raise CredentialNotFoundError

0 commit comments

Comments
 (0)