|
31 | 31 | import shutil |
32 | 32 | import subprocess # nosec B404 |
33 | 33 | import sys |
34 | | -from typing import Any, Dict, Iterator, List, Optional, Tuple, Union |
35 | | -from urllib.parse import ParseResult, urlparse |
| 34 | +from typing import Any, Dict, List, Optional, Tuple, Union |
| 35 | +from urllib.parse import urlparse |
36 | 36 |
|
37 | | -from dulwich.config import ConfigDict, StackedConfig |
| 37 | +from dulwich.config import StackedConfig |
| 38 | +from dulwich.credentials import urlmatch_credential_sections |
38 | 39 |
|
39 | 40 | SectionLike = Union[bytes, str, Tuple[Union[bytes, str], ...]] |
40 | 41 |
|
41 | 42 |
|
42 | | -def match_urls(url: ParseResult, url_prefix: ParseResult) -> bool: |
43 | | - base_match = ( |
44 | | - url.scheme == url_prefix.scheme |
45 | | - and url.hostname == url_prefix.hostname |
46 | | - and url.port == url_prefix.port |
47 | | - ) |
48 | | - user_match = url.username == url_prefix.username if url_prefix.username else True |
49 | | - path_match = url.path.rstrip("/").startswith(url_prefix.path.rstrip()) |
50 | | - return base_match and user_match and path_match |
51 | | - |
52 | | - |
53 | | -def match_partial_url(valid_url: ParseResult, partial_url: str) -> bool: |
54 | | - """matches a parsed url with a partial url (no scheme/netloc)""" |
55 | | - if "://" not in partial_url: |
56 | | - parsed = urlparse("scheme://" + partial_url) |
57 | | - else: |
58 | | - parsed = urlparse(partial_url) |
59 | | - if valid_url.scheme != parsed.scheme: |
60 | | - return False |
61 | | - |
62 | | - if any( |
63 | | - ( |
64 | | - (parsed.hostname and valid_url.hostname != parsed.hostname), |
65 | | - (parsed.username and valid_url.username != parsed.username), |
66 | | - (parsed.port and valid_url.port != parsed.port), |
67 | | - (parsed.path and parsed.path.rstrip("/") != valid_url.path.rstrip("/")), |
68 | | - ), |
69 | | - ): |
70 | | - return False |
71 | | - |
72 | | - return True |
73 | | - |
74 | | - |
75 | | -def urlmatch_credential_sections( |
76 | | - config: ConfigDict, url: Optional[str] |
77 | | -) -> Iterator[SectionLike]: |
78 | | - """Returns credential sections from the config which match the given URL""" |
79 | | - encoding = config.encoding or sys.getdefaultencoding() |
80 | | - parsed_url = urlparse(url or "") |
81 | | - for config_section in config.sections(): |
82 | | - if config_section[0] != b"credential": |
83 | | - continue |
84 | | - |
85 | | - if len(config_section) < 2: |
86 | | - yield config_section |
87 | | - continue |
88 | | - |
89 | | - config_url = config_section[1].decode(encoding) |
90 | | - parsed_config_url = urlparse(config_url) |
91 | | - if parsed_config_url.scheme and parsed_config_url.netloc: |
92 | | - is_match = match_urls(parsed_url, parsed_config_url) |
93 | | - else: |
94 | | - is_match = match_partial_url(parsed_url, config_url) |
95 | | - |
96 | | - if is_match: |
97 | | - yield config_section |
98 | | - |
99 | | - |
100 | 43 | class CredentialNotFoundError(Exception): |
101 | 44 | """Error occurred while retrieving credentials/no credentials available.""" |
102 | 45 |
|
|
0 commit comments