@@ -1007,156 +1007,11 @@ pub fn fetch(
1007
1007
}
1008
1008
1009
1009
if let Some ( true ) = gctx. net_config ( ) ?. git_fetch_with_cli {
1010
- return fetch_with_cli ( repo, remote_url, & refspecs, tags, gctx) ;
1011
- }
1012
-
1013
- if gctx. cli_unstable ( ) . gitoxide . map_or ( false , |git| git. fetch ) {
1014
- let git2_repo = repo;
1015
- let config_overrides = cargo_config_to_gitoxide_overrides ( gctx) ?;
1016
- let repo_reinitialized = AtomicBool :: default ( ) ;
1017
- let res = oxide:: with_retry_and_progress (
1018
- & git2_repo. path ( ) . to_owned ( ) ,
1019
- gctx,
1020
- & |repo_path,
1021
- should_interrupt,
1022
- mut progress,
1023
- url_for_authentication : & mut dyn FnMut ( & gix:: bstr:: BStr ) | {
1024
- // The `fetch` operation here may fail spuriously due to a corrupt
1025
- // repository. It could also fail, however, for a whole slew of other
1026
- // reasons (aka network related reasons). We want Cargo to automatically
1027
- // recover from corrupt repositories, but we don't want Cargo to stomp
1028
- // over other legitimate errors.
1029
- //
1030
- // Consequently we save off the error of the `fetch` operation and if it
1031
- // looks like a "corrupt repo" error then we blow away the repo and try
1032
- // again. If it looks like any other kind of error, or if we've already
1033
- // blown away the repository, then we want to return the error as-is.
1034
- loop {
1035
- let res = oxide:: open_repo (
1036
- repo_path,
1037
- config_overrides. clone ( ) ,
1038
- oxide:: OpenMode :: ForFetch ,
1039
- )
1040
- . map_err ( crate :: sources:: git:: fetch:: Error :: from)
1041
- . and_then ( |repo| {
1042
- debug ! ( "initiating fetch of {refspecs:?} from {remote_url}" ) ;
1043
- let url_for_authentication = & mut * url_for_authentication;
1044
- let remote = repo
1045
- . remote_at ( remote_url) ?
1046
- . with_fetch_tags ( if tags {
1047
- gix:: remote:: fetch:: Tags :: All
1048
- } else {
1049
- gix:: remote:: fetch:: Tags :: Included
1050
- } )
1051
- . with_refspecs (
1052
- refspecs. iter ( ) . map ( |s| s. as_str ( ) ) ,
1053
- gix:: remote:: Direction :: Fetch ,
1054
- )
1055
- . map_err ( crate :: sources:: git:: fetch:: Error :: Other ) ?;
1056
- let url = remote
1057
- . url ( gix:: remote:: Direction :: Fetch )
1058
- . expect ( "set at init" )
1059
- . to_owned ( ) ;
1060
- let connection = remote. connect ( gix:: remote:: Direction :: Fetch ) ?;
1061
- let mut authenticate = connection. configured_credentials ( url) ?;
1062
- let connection = connection. with_credentials (
1063
- move |action : gix:: protocol:: credentials:: helper:: Action | {
1064
- if let Some ( url) = action. context ( ) . and_then ( |gctx| {
1065
- gctx. url . as_ref ( ) . filter ( |url| * url != remote_url)
1066
- } ) {
1067
- url_for_authentication ( url. as_ref ( ) ) ;
1068
- }
1069
- authenticate ( action)
1070
- } ,
1071
- ) ;
1072
- let outcome = connection
1073
- . prepare_fetch ( & mut progress, gix:: remote:: ref_map:: Options :: default ( ) ) ?
1074
- . with_shallow ( shallow. clone ( ) . into ( ) )
1075
- . receive ( & mut progress, should_interrupt) ?;
1076
- Ok ( outcome)
1077
- } ) ;
1078
- let err = match res {
1079
- Ok ( _) => break ,
1080
- Err ( e) => e,
1081
- } ;
1082
- debug ! ( "fetch failed: {}" , err) ;
1083
-
1084
- if !repo_reinitialized. load ( Ordering :: Relaxed )
1085
- // We check for errors that could occur if the configuration, refs or odb files are corrupted.
1086
- // We don't check for errors related to writing as `gitoxide` is expected to create missing leading
1087
- // folder before writing files into it, or else not even open a directory as git repository (which is
1088
- // also handled here).
1089
- && err. is_corrupted ( )
1090
- || has_shallow_lock_file ( & err)
1091
- {
1092
- repo_reinitialized. store ( true , Ordering :: Relaxed ) ;
1093
- debug ! (
1094
- "looks like this is a corrupt repository, reinitializing \
1095
- and trying again"
1096
- ) ;
1097
- if oxide:: reinitialize ( repo_path) . is_ok ( ) {
1098
- continue ;
1099
- }
1100
- }
1101
-
1102
- return Err ( err. into ( ) ) ;
1103
- }
1104
- Ok ( ( ) )
1105
- } ,
1106
- ) ;
1107
- if repo_reinitialized. load ( Ordering :: Relaxed ) {
1108
- * git2_repo = git2:: Repository :: open ( git2_repo. path ( ) ) ?;
1109
- }
1110
- res
1010
+ fetch_with_cli ( repo, remote_url, & refspecs, tags, gctx)
1011
+ } else if gctx. cli_unstable ( ) . gitoxide . map_or ( false , |git| git. fetch ) {
1012
+ fetch_with_gitoxide ( repo, remote_url, refspecs, tags, shallow, gctx)
1111
1013
} else {
1112
- debug ! ( "doing a fetch for {remote_url}" ) ;
1113
- let git_config = git2:: Config :: open_default ( ) ?;
1114
- with_fetch_options ( & git_config, remote_url, gctx, & mut |mut opts| {
1115
- if tags {
1116
- opts. download_tags ( git2:: AutotagOption :: All ) ;
1117
- }
1118
- if let gix:: remote:: fetch:: Shallow :: DepthAtRemote ( depth) = shallow {
1119
- opts. depth ( 0i32 . saturating_add_unsigned ( depth. get ( ) ) ) ;
1120
- }
1121
- // The `fetch` operation here may fail spuriously due to a corrupt
1122
- // repository. It could also fail, however, for a whole slew of other
1123
- // reasons (aka network related reasons). We want Cargo to automatically
1124
- // recover from corrupt repositories, but we don't want Cargo to stomp
1125
- // over other legitimate errors.
1126
- //
1127
- // Consequently we save off the error of the `fetch` operation and if it
1128
- // looks like a "corrupt repo" error then we blow away the repo and try
1129
- // again. If it looks like any other kind of error, or if we've already
1130
- // blown away the repository, then we want to return the error as-is.
1131
- let mut repo_reinitialized = false ;
1132
- loop {
1133
- debug ! ( "initiating fetch of {refspecs:?} from {remote_url}" ) ;
1134
- let res =
1135
- repo. remote_anonymous ( remote_url) ?
1136
- . fetch ( & refspecs, Some ( & mut opts) , None ) ;
1137
- let err = match res {
1138
- Ok ( ( ) ) => break ,
1139
- Err ( e) => e,
1140
- } ;
1141
- debug ! ( "fetch failed: {}" , err) ;
1142
-
1143
- if !repo_reinitialized
1144
- && matches ! ( err. class( ) , ErrorClass :: Reference | ErrorClass :: Odb )
1145
- {
1146
- repo_reinitialized = true ;
1147
- debug ! (
1148
- "looks like this is a corrupt repository, reinitializing \
1149
- and trying again"
1150
- ) ;
1151
- if reinitialize ( repo) . is_ok ( ) {
1152
- continue ;
1153
- }
1154
- }
1155
-
1156
- return Err ( err. into ( ) ) ;
1157
- }
1158
- Ok ( ( ) )
1159
- } )
1014
+ fetch_with_libgit2 ( repo, remote_url, refspecs, tags, shallow, gctx)
1160
1015
}
1161
1016
}
1162
1017
@@ -1227,6 +1082,171 @@ fn fetch_with_cli(
1227
1082
Ok ( ( ) )
1228
1083
}
1229
1084
1085
+ fn fetch_with_gitoxide (
1086
+ repo : & mut git2:: Repository ,
1087
+ remote_url : & str ,
1088
+ refspecs : Vec < String > ,
1089
+ tags : bool ,
1090
+ shallow : gix:: remote:: fetch:: Shallow ,
1091
+ gctx : & GlobalContext ,
1092
+ ) -> CargoResult < ( ) > {
1093
+ let git2_repo = repo;
1094
+ let config_overrides = cargo_config_to_gitoxide_overrides ( gctx) ?;
1095
+ let repo_reinitialized = AtomicBool :: default ( ) ;
1096
+ let res = oxide:: with_retry_and_progress (
1097
+ & git2_repo. path ( ) . to_owned ( ) ,
1098
+ gctx,
1099
+ & |repo_path,
1100
+ should_interrupt,
1101
+ mut progress,
1102
+ url_for_authentication : & mut dyn FnMut ( & gix:: bstr:: BStr ) | {
1103
+ // The `fetch` operation here may fail spuriously due to a corrupt
1104
+ // repository. It could also fail, however, for a whole slew of other
1105
+ // reasons (aka network related reasons). We want Cargo to automatically
1106
+ // recover from corrupt repositories, but we don't want Cargo to stomp
1107
+ // over other legitimate errors.
1108
+ //
1109
+ // Consequently we save off the error of the `fetch` operation and if it
1110
+ // looks like a "corrupt repo" error then we blow away the repo and try
1111
+ // again. If it looks like any other kind of error, or if we've already
1112
+ // blown away the repository, then we want to return the error as-is.
1113
+ loop {
1114
+ let res = oxide:: open_repo (
1115
+ repo_path,
1116
+ config_overrides. clone ( ) ,
1117
+ oxide:: OpenMode :: ForFetch ,
1118
+ )
1119
+ . map_err ( crate :: sources:: git:: fetch:: Error :: from)
1120
+ . and_then ( |repo| {
1121
+ debug ! ( "initiating fetch of {refspecs:?} from {remote_url}" ) ;
1122
+ let url_for_authentication = & mut * url_for_authentication;
1123
+ let remote = repo
1124
+ . remote_at ( remote_url) ?
1125
+ . with_fetch_tags ( if tags {
1126
+ gix:: remote:: fetch:: Tags :: All
1127
+ } else {
1128
+ gix:: remote:: fetch:: Tags :: Included
1129
+ } )
1130
+ . with_refspecs (
1131
+ refspecs. iter ( ) . map ( |s| s. as_str ( ) ) ,
1132
+ gix:: remote:: Direction :: Fetch ,
1133
+ )
1134
+ . map_err ( crate :: sources:: git:: fetch:: Error :: Other ) ?;
1135
+ let url = remote
1136
+ . url ( gix:: remote:: Direction :: Fetch )
1137
+ . expect ( "set at init" )
1138
+ . to_owned ( ) ;
1139
+ let connection = remote. connect ( gix:: remote:: Direction :: Fetch ) ?;
1140
+ let mut authenticate = connection. configured_credentials ( url) ?;
1141
+ let connection = connection. with_credentials (
1142
+ move |action : gix:: protocol:: credentials:: helper:: Action | {
1143
+ if let Some ( url) = action
1144
+ . context ( )
1145
+ . and_then ( |gctx| gctx. url . as_ref ( ) . filter ( |url| * url != remote_url) )
1146
+ {
1147
+ url_for_authentication ( url. as_ref ( ) ) ;
1148
+ }
1149
+ authenticate ( action)
1150
+ } ,
1151
+ ) ;
1152
+ let outcome = connection
1153
+ . prepare_fetch ( & mut progress, gix:: remote:: ref_map:: Options :: default ( ) ) ?
1154
+ . with_shallow ( shallow. clone ( ) . into ( ) )
1155
+ . receive ( & mut progress, should_interrupt) ?;
1156
+ Ok ( outcome)
1157
+ } ) ;
1158
+ let err = match res {
1159
+ Ok ( _) => break ,
1160
+ Err ( e) => e,
1161
+ } ;
1162
+ debug ! ( "fetch failed: {}" , err) ;
1163
+
1164
+ if !repo_reinitialized. load ( Ordering :: Relaxed )
1165
+ // We check for errors that could occur if the configuration, refs or odb files are corrupted.
1166
+ // We don't check for errors related to writing as `gitoxide` is expected to create missing leading
1167
+ // folder before writing files into it, or else not even open a directory as git repository (which is
1168
+ // also handled here).
1169
+ && err. is_corrupted ( )
1170
+ || has_shallow_lock_file ( & err)
1171
+ {
1172
+ repo_reinitialized. store ( true , Ordering :: Relaxed ) ;
1173
+ debug ! (
1174
+ "looks like this is a corrupt repository, reinitializing \
1175
+ and trying again"
1176
+ ) ;
1177
+ if oxide:: reinitialize ( repo_path) . is_ok ( ) {
1178
+ continue ;
1179
+ }
1180
+ }
1181
+
1182
+ return Err ( err. into ( ) ) ;
1183
+ }
1184
+ Ok ( ( ) )
1185
+ } ,
1186
+ ) ;
1187
+ if repo_reinitialized. load ( Ordering :: Relaxed ) {
1188
+ * git2_repo = git2:: Repository :: open ( git2_repo. path ( ) ) ?;
1189
+ }
1190
+ res
1191
+ }
1192
+
1193
+ fn fetch_with_libgit2 (
1194
+ repo : & mut git2:: Repository ,
1195
+ remote_url : & str ,
1196
+ refspecs : Vec < String > ,
1197
+ tags : bool ,
1198
+ shallow : gix:: remote:: fetch:: Shallow ,
1199
+ gctx : & GlobalContext ,
1200
+ ) -> CargoResult < ( ) > {
1201
+ debug ! ( "doing a fetch for {remote_url}" ) ;
1202
+ let git_config = git2:: Config :: open_default ( ) ?;
1203
+ with_fetch_options ( & git_config, remote_url, gctx, & mut |mut opts| {
1204
+ if tags {
1205
+ opts. download_tags ( git2:: AutotagOption :: All ) ;
1206
+ }
1207
+ if let gix:: remote:: fetch:: Shallow :: DepthAtRemote ( depth) = shallow {
1208
+ opts. depth ( 0i32 . saturating_add_unsigned ( depth. get ( ) ) ) ;
1209
+ }
1210
+ // The `fetch` operation here may fail spuriously due to a corrupt
1211
+ // repository. It could also fail, however, for a whole slew of other
1212
+ // reasons (aka network related reasons). We want Cargo to automatically
1213
+ // recover from corrupt repositories, but we don't want Cargo to stomp
1214
+ // over other legitimate errors.
1215
+ //
1216
+ // Consequently we save off the error of the `fetch` operation and if it
1217
+ // looks like a "corrupt repo" error then we blow away the repo and try
1218
+ // again. If it looks like any other kind of error, or if we've already
1219
+ // blown away the repository, then we want to return the error as-is.
1220
+ let mut repo_reinitialized = false ;
1221
+ loop {
1222
+ debug ! ( "initiating fetch of {refspecs:?} from {remote_url}" ) ;
1223
+ let res = repo
1224
+ . remote_anonymous ( remote_url) ?
1225
+ . fetch ( & refspecs, Some ( & mut opts) , None ) ;
1226
+ let err = match res {
1227
+ Ok ( ( ) ) => break ,
1228
+ Err ( e) => e,
1229
+ } ;
1230
+ debug ! ( "fetch failed: {}" , err) ;
1231
+
1232
+ if !repo_reinitialized && matches ! ( err. class( ) , ErrorClass :: Reference | ErrorClass :: Odb )
1233
+ {
1234
+ repo_reinitialized = true ;
1235
+ debug ! (
1236
+ "looks like this is a corrupt repository, reinitializing \
1237
+ and trying again"
1238
+ ) ;
1239
+ if reinitialize ( repo) . is_ok ( ) {
1240
+ continue ;
1241
+ }
1242
+ }
1243
+
1244
+ return Err ( err. into ( ) ) ;
1245
+ }
1246
+ Ok ( ( ) )
1247
+ } )
1248
+ }
1249
+
1230
1250
/// Attempts to `git gc` a repository.
1231
1251
///
1232
1252
/// Cargo has a bunch of long-lived git repositories in its global cache and
0 commit comments