Skip to content

Commit f520132

Browse files
committed
Add fetch_url and push_url to GitRemoteCmd
1 parent 5265a53 commit f520132

File tree

1 file changed

+88
-11
lines changed

1 file changed

+88
-11
lines changed

src/libvcs/cmd/git.py

+88-11
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import datetime
66
import pathlib
7+
import re
78
import shlex
89
import typing as t
910
from collections.abc import Sequence
@@ -2361,12 +2362,16 @@ class GitRemoteCmd:
23612362
"""Run commands directly for a git remote on a git repository."""
23622363

23632364
remote_name: str
2365+
fetch_url: str | None
2366+
push_url: str | None
23642367

23652368
def __init__(
23662369
self,
23672370
*,
23682371
path: StrPath,
23692372
remote_name: str,
2373+
fetch_url: str | None = None,
2374+
push_url: str | None = None,
23702375
cmd: Git | None = None,
23712376
) -> None:
23722377
r"""Lite, typed, pythonic wrapper for git-remote(1).
@@ -2408,6 +2413,8 @@ def __init__(
24082413
self.cmd = cmd if isinstance(cmd, Git) else Git(path=self.path)
24092414

24102415
self.remote_name = remote_name
2416+
self.fetch_url = fetch_url
2417+
self.push_url = push_url
24112418

24122419
def __repr__(self) -> str:
24132420
"""Representation of a git remote for a git repository."""
@@ -2731,6 +2738,24 @@ def set_url(
27312738
)
27322739

27332740

2741+
GitRemoteManagerLiteral = Literal[
2742+
"--verbose",
2743+
"add",
2744+
"rename",
2745+
"remove",
2746+
"set-branches",
2747+
"set-head",
2748+
"set-branch",
2749+
"get-url",
2750+
"set-url",
2751+
"set-url --add",
2752+
"set-url --delete",
2753+
"prune",
2754+
"show",
2755+
"update",
2756+
]
2757+
2758+
27342759
class GitRemoteManager:
27352760
"""Run commands directly related to git remotes of a git repo."""
27362761

@@ -2777,7 +2802,7 @@ def __repr__(self) -> str:
27772802

27782803
def run(
27792804
self,
2780-
command: GitRemoteCommandLiteral | None = None,
2805+
command: GitRemoteManagerLiteral | None = None,
27812806
local_flags: list[str] | None = None,
27822807
*,
27832808
# Pass-through to run()
@@ -2860,6 +2885,16 @@ def show(
28602885
--------
28612886
>>> GitRemoteManager(path=example_git_repo.path).show()
28622887
'origin'
2888+
2889+
For the example below, add a remote:
2890+
>>> GitRemoteManager(path=example_git_repo.path).add(
2891+
... name='my_remote', url=f'file:///dev/null'
2892+
... )
2893+
''
2894+
2895+
Retrieve a list of remote names:
2896+
>>> GitRemoteManager(path=example_git_repo.path).show().splitlines()
2897+
['my_remote', 'origin']
28632898
"""
28642899
local_flags: list[str] = []
28652900
required_flags: list[str] = []
@@ -2880,17 +2915,17 @@ def show(
28802915
log_in_real_time=log_in_real_time,
28812916
)
28822917

2883-
def _ls(self) -> list[str]:
2884-
"""List remotes.
2918+
def _ls(self) -> str:
2919+
r"""List remotes (raw output).
28852920
28862921
Examples
28872922
--------
28882923
>>> GitRemoteManager(path=example_git_repo.path)._ls()
2889-
['origin']
2924+
'origin\tfile:///... (fetch)\norigin\tfile:///... (push)'
28902925
"""
28912926
return self.run(
2892-
"show",
2893-
).splitlines()
2927+
"--verbose",
2928+
)
28942929

28952930
def ls(self) -> QueryList[GitRemoteCmd]:
28962931
"""List remotes.
@@ -2899,14 +2934,56 @@ def ls(self) -> QueryList[GitRemoteCmd]:
28992934
--------
29002935
>>> GitRemoteManager(path=example_git_repo.path).ls()
29012936
[<GitRemoteCmd path=... remote_name=origin>]
2937+
2938+
For the example below, add a remote:
2939+
>>> GitRemoteManager(path=example_git_repo.path).add(
2940+
... name='my_remote', url=f'file:///dev/null'
2941+
... )
2942+
''
2943+
2944+
>>> GitRemoteManager(path=example_git_repo.path).ls()
2945+
[<GitRemoteCmd path=... remote_name=my_remote>,
2946+
<GitRemoteCmd path=... remote_name=origin>]
29022947
"""
2903-
return QueryList(
2904-
[
2905-
GitRemoteCmd(path=self.path, remote_name=remote_name.lstrip("* "))
2906-
for remote_name in self._ls()
2907-
],
2948+
remote_str = self._ls()
2949+
remote_pattern = re.compile(
2950+
r"""
2951+
(?P<name>\S+) # Remote name: one or more non-whitespace characters
2952+
\s+ # One or more whitespace characters
2953+
(?P<url>\S+) # URL: one or more non-whitespace characters
2954+
\s+ # One or more whitespace characters
2955+
\((?P<cmd_type>fetch|push)\) # 'fetch' or 'push' in parentheses
2956+
""",
2957+
re.VERBOSE | re.MULTILINE,
29082958
)
29092959

2960+
remotes: dict[str, dict[str, str | None]] = {}
2961+
2962+
for match_obj in remote_pattern.finditer(remote_str):
2963+
name = match_obj.group("name")
2964+
url = match_obj.group("url")
2965+
cmd_type = match_obj.group("cmd_type")
2966+
2967+
if name not in remotes:
2968+
remotes[name] = {}
2969+
2970+
remotes[name][cmd_type] = url
2971+
2972+
remote_cmds: list[GitRemoteCmd] = []
2973+
for name, urls in remotes.items():
2974+
fetch_url = urls.get("fetch")
2975+
push_url = urls.get("push")
2976+
remote_cmds.append(
2977+
GitRemoteCmd(
2978+
path=self.path,
2979+
remote_name=name,
2980+
fetch_url=fetch_url,
2981+
push_url=push_url,
2982+
)
2983+
)
2984+
2985+
return QueryList(remote_cmds)
2986+
29102987
def get(self, *args: t.Any, **kwargs: t.Any) -> GitRemoteCmd | None:
29112988
"""Get remote via filter lookup.
29122989

0 commit comments

Comments
 (0)