@@ -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