@@ -776,7 +776,7 @@ pub fn with_fetch_options(
776776
777777pub  fn  fetch ( 
778778    repo :  & mut  git2:: Repository , 
779-     url :  & str , 
779+     orig_url :  & str , 
780780    reference :  & GitReference , 
781781    config :  & Config , 
782782)  -> CargoResult < ( ) >  { 
@@ -792,7 +792,7 @@ pub fn fetch(
792792
793793    // If we're fetching from GitHub, attempt GitHub's special fast path for 
794794    // testing if we've already got an up-to-date copy of the repository 
795-     let  oid_to_fetch = match  github_fast_path ( repo,  url ,  reference,  config)  { 
795+     let  oid_to_fetch = match  github_fast_path ( repo,  orig_url ,  reference,  config)  { 
796796        Ok ( FastPathRev :: UpToDate )  => return  Ok ( ( ) ) , 
797797        Ok ( FastPathRev :: NeedsFetch ( rev) )  => Some ( rev) , 
798798        Ok ( FastPathRev :: Indeterminate )  => None , 
@@ -854,20 +854,19 @@ pub fn fetch(
854854    // flavors of authentication possible while also still giving us all the 
855855    // speed and portability of using `libgit2`. 
856856    if  let  Some ( true )  = config. net_config ( ) ?. git_fetch_with_cli  { 
857-         return  fetch_with_cli ( repo,  url ,  & refspecs,  tags,  config) ; 
857+         return  fetch_with_cli ( repo,  orig_url ,  & refspecs,  tags,  config) ; 
858858    } 
859859    if  config
860860        . cli_unstable ( ) 
861861        . gitoxide 
862862        . map_or ( false ,  |git| git. fetch ) 
863863    { 
864-         use  git:: remote:: fetch:: Error ; 
865864        use  git_repository as  git; 
866865        let  git2_repo = repo; 
867866        oxide:: with_retry_and_progress ( 
868867            & git2_repo. path ( ) . to_owned ( ) , 
869868            config, 
870-             & mut  |repo ,  should_interrupt,  mut  progress| { 
869+             & mut  |repo_path ,  should_interrupt,  mut  progress,  url_for_authentication | { 
871870                // The `fetch` operation here may fail spuriously due to a corrupt 
872871                // repository. It could also fail, however, for a whole slew of other 
873872                // reasons (aka network related reasons). We want Cargo to automatically 
@@ -879,44 +878,93 @@ pub fn fetch(
879878                // again. If it looks like any other kind of error, or if we've already 
880879                // blown away the repository, then we want to return the error as-is. 
881880                let  mut  repo_reinitialized = false ; 
882-                 let  mut  repo_storage; 
883-                 let  mut  repo = & * repo; 
884881                loop  { 
885-                     debug ! ( "initiating fetch of {:?} from {}" ,  refspecs,  url) ; 
886-                     let  res = repo
887-                         . remote_at ( url) ?
888-                         . with_refspecs ( 
889-                             refspecs. iter ( ) . map ( |s| s. as_str ( ) ) , 
890-                             git:: remote:: Direction :: Fetch , 
891-                         ) ?
892-                         . connect ( git:: remote:: Direction :: Fetch ,  & mut  progress) ?
893-                         . prepare_fetch ( git:: remote:: ref_map:: Options :: default ( ) ) ?
894-                         . receive ( should_interrupt) ; 
882+                     let  repo = oxide:: open_repo ( repo_path,  config) ; 
883+                     let  res = match  repo { 
884+                         Ok ( repo)  => { 
885+                             debug ! ( "initiating fetch of {:?} from {}" ,  refspecs,  orig_url) ; 
886+                             ( { 
887+                                 let  url_for_authentication = & mut  * url_for_authentication; 
888+                                 || -> CargoResult < _ >  { 
889+                                     let  remote = repo. remote_at ( orig_url) ?. with_refspecs ( 
890+                                         refspecs. iter ( ) . map ( |s| s. as_str ( ) ) , 
891+                                         git:: remote:: Direction :: Fetch , 
892+                                     ) ?; 
893+                                     let  url = remote
894+                                         . url ( git:: remote:: Direction :: Fetch ) 
895+                                         . expect ( "set at init" ) 
896+                                         . to_owned ( ) ; 
897+                                     let  connection = remote
898+                                         . connect ( git:: remote:: Direction :: Fetch ,  & mut  progress) ?; 
899+                                     let  mut  authenticate =
900+                                         connection. configured_credentials ( url) ?; 
901+                                     let  connection = connection. with_credentials ( 
902+                                     move  |action :  git:: protocol:: credentials:: helper:: Action | { 
903+                                         if  let  Some ( url)  =
904+                                             action. context ( ) . and_then ( |ctx| ctx. url . as_ref ( ) . filter ( |url| * url != orig_url) ) 
905+                                         { 
906+                                             url_for_authentication ( url. as_ref ( ) ) ; 
907+                                         } 
908+                                         authenticate ( action) 
909+                                     } , 
910+                                 ) ; 
911+                                     let  outcome = connection
912+                                         . prepare_fetch ( git:: remote:: ref_map:: Options :: default ( ) ) ?
913+                                         . receive ( should_interrupt) ?; 
914+                                     Ok ( outcome) 
915+                                 } 
916+                             } ) ( ) 
917+                         } 
918+                         Err ( err)  => Err ( err) , 
919+                     } ; 
895920                    let  err = match  res { 
896921                        Ok ( _)  => break , 
897922                        Err ( e)  => e, 
898923                    } ; 
899924                    debug ! ( "fetch failed: {}" ,  err) ; 
900925
901926                    if  !repo_reinitialized
902-                         && matches ! ( 
903-                             err, 
904-                             Error :: Configuration  {  .. } 
905-                                 | Error :: IncompatibleObjectHash  {  .. } 
906-                                 | Error :: WritePack ( _) 
907-                                 | Error :: UpdateRefs ( _) 
908-                                 | Error :: RemovePackKeepFile  {  .. } 
909-                         ) 
927+                         // We check for errors that could occour if the configuration, refs or odb files are corrupted. 
928+                         // We don't check for errors related to writing as `gitoxide` is expected to create missing leading 
929+                         // folder before writing files into it, or else not even open a directory as git repository (which is 
930+                         // also handled here). 
931+                         && err. downcast_ref :: < git:: open:: Error > ( ) . map_or ( false ,  |err| { 
932+                             use  git:: open:: Error ; 
933+                             matches ! ( 
934+                                 err, 
935+                                 Error :: NotARepository  {  .. } | Error :: Config ( _) 
936+                             ) 
937+                         } ) 
938+                         || err
939+                             . downcast_ref :: < git:: remote:: fetch:: prepare:: Error > ( ) 
940+                             . map_or ( false ,  |err| match  err { 
941+                                 git:: remote:: fetch:: prepare:: Error :: RefMap ( err)  => { 
942+                                     use  git:: remote:: ref_map:: Error ; 
943+                                     matches ! ( 
944+                                         err, 
945+                                         Error :: ListRefs ( _) 
946+                                             | Error :: GatherTransportConfig  {  .. } 
947+                                             | Error :: ConfigureCredentials ( _) 
948+                                     ) 
949+                                 } 
950+                                 _ => false , 
951+                             } ) 
952+                         || err
953+                             . downcast_ref :: < git:: remote:: fetch:: Error > ( ) 
954+                             . map_or ( false ,  |err| { 
955+                                 use  git:: remote:: fetch:: Error ; 
956+                                 matches ! ( 
957+                                     err, 
958+                                     Error :: Configuration  {  .. }  | Error :: RemovePackKeepFile  {  .. } 
959+                                 ) 
960+                             } ) 
910961                    { 
911962                        repo_reinitialized = true ; 
912963                        debug ! ( 
913964                            "looks like this is a corrupt repository, reinitializing \  
914965                      and trying again"
915966                        ) ; 
916967                        if  reinitialize ( git2_repo) . is_ok ( )  { 
917-                             repo_storage =
918-                                 git:: open_opts ( repo. path ( ) ,  repo. open_options ( ) . to_owned ( ) ) ?; 
919-                             repo = & repo_storage; 
920968                            continue ; 
921969                        } 
922970                    } 
@@ -927,9 +975,9 @@ pub fn fetch(
927975            } , 
928976        ) 
929977    }  else  { 
930-         debug ! ( "doing a fetch for {}" ,  url ) ; 
978+         debug ! ( "doing a fetch for {}" ,  orig_url ) ; 
931979        let  git_config = git2:: Config :: open_default ( ) ?; 
932-         with_fetch_options ( & git_config,  url ,  config,  & mut  |mut  opts| { 
980+         with_fetch_options ( & git_config,  orig_url ,  config,  & mut  |mut  opts| { 
933981            if  tags { 
934982                opts. download_tags ( git2:: AutotagOption :: All ) ; 
935983            } 
@@ -945,9 +993,9 @@ pub fn fetch(
945993            // blown away the repository, then we want to return the error as-is. 
946994            let  mut  repo_reinitialized = false ; 
947995            loop  { 
948-                 debug ! ( "initiating fetch of {:?} from {}" ,  refspecs,  url ) ; 
996+                 debug ! ( "initiating fetch of {:?} from {}" ,  refspecs,  orig_url ) ; 
949997                let  res = repo
950-                     . remote_anonymous ( url ) ?
998+                     . remote_anonymous ( orig_url ) ?
951999                    . fetch ( & refspecs,  Some ( & mut  opts) ,  None ) ; 
9521000                let  err = match  res { 
9531001                    Ok ( ( ) )  => break , 
0 commit comments