44
55import  datetime 
66import  pathlib 
7+ import  re 
78import  shlex 
89import  typing  as  t 
910from  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+ 
27342759class  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