@@ -23,6 +23,10 @@ use std::sync::atomic::{AtomicBool, Ordering};
23
23
use std:: time:: { Duration , Instant } ;
24
24
use url:: Url ;
25
25
26
+ /// A file indicates that if present, `git reset` has been done and a repo
27
+ /// checkout is ready to go. See [`GitCheckout::reset`] for why we need this.
28
+ const CHECKOUT_READY_LOCK : & str = ".cargo-ok" ;
29
+
26
30
fn serialize_str < T , S > ( t : & T , s : S ) -> Result < S :: Ok , S :: Error >
27
31
where
28
32
T : fmt:: Display ,
@@ -53,29 +57,24 @@ pub struct GitRemote {
53
57
54
58
/// A local clone of a remote repository's database. Multiple [`GitCheckout`]s
55
59
/// can be cloned from a single [`GitDatabase`].
56
- #[ derive( Serialize ) ]
57
60
pub struct GitDatabase {
58
61
/// The remote repository where this database is fetched from.
59
62
remote : GitRemote ,
60
63
/// Path to the root of the underlying Git repository on the local filesystem.
61
64
path : PathBuf ,
62
65
/// Underlying Git repository instance for this database.
63
- #[ serde( skip_serializing) ]
64
66
repo : git2:: Repository ,
65
67
}
66
68
67
69
/// A local checkout of a particular revision from a [`GitDatabase`].
68
- #[ derive( Serialize ) ]
69
70
pub struct GitCheckout < ' a > {
70
71
/// The git database where this checkout is cloned from.
71
72
database : & ' a GitDatabase ,
72
73
/// Path to the root of the underlying Git repository on the local filesystem.
73
- location : PathBuf ,
74
+ path : PathBuf ,
74
75
/// The git revision this checkout is for.
75
- #[ serde( serialize_with = "serialize_str" ) ]
76
76
revision : git2:: Oid ,
77
77
/// Underlying Git repository instance for this checkout.
78
- #[ serde( skip_serializing) ]
79
78
repo : git2:: Repository ,
80
79
}
81
80
@@ -90,10 +89,6 @@ impl GitRemote {
90
89
& self . url
91
90
}
92
91
93
- pub fn rev_for ( & self , path : & Path , reference : & GitReference ) -> CargoResult < git2:: Oid > {
94
- reference. resolve ( & self . db_at ( path) ?. repo )
95
- }
96
-
97
92
/// Fetches and checkouts to a reference or a revision from this remote
98
93
/// into a local path.
99
94
///
@@ -184,21 +179,20 @@ impl GitDatabase {
184
179
rev : git2:: Oid ,
185
180
dest : & Path ,
186
181
cargo_config : & Config ,
187
- parent_remote_url : & Url ,
188
182
) -> CargoResult < GitCheckout < ' _ > > {
189
183
// If the existing checkout exists, and it is fresh, use it.
190
184
// A non-fresh checkout can happen if the checkout operation was
191
185
// interrupted. In that case, the checkout gets deleted and a new
192
186
// clone is created.
193
187
let checkout = match git2:: Repository :: open ( dest)
194
188
. ok ( )
195
- . map ( |repo| GitCheckout :: new ( dest , self , rev, repo) )
189
+ . map ( |repo| GitCheckout :: new ( self , rev, repo) )
196
190
. filter ( |co| co. is_fresh ( ) )
197
191
{
198
192
Some ( co) => co,
199
193
None => GitCheckout :: clone_into ( dest, self , rev, cargo_config) ?,
200
194
} ;
201
- checkout. update_submodules ( cargo_config, parent_remote_url ) ?;
195
+ checkout. update_submodules ( cargo_config) ?;
202
196
Ok ( checkout)
203
197
}
204
198
@@ -270,21 +264,26 @@ impl<'a> GitCheckout<'a> {
270
264
/// is done. Use [`GitCheckout::is_fresh`] to check.
271
265
///
272
266
/// * The `database` is where this checkout is from.
273
- /// * The `repo` will be the checked out Git repoistory at `path` .
267
+ /// * The `repo` will be the checked out Git repoistory.
274
268
fn new (
275
- path : & Path ,
276
269
database : & ' a GitDatabase ,
277
270
revision : git2:: Oid ,
278
271
repo : git2:: Repository ,
279
272
) -> GitCheckout < ' a > {
273
+ let path = repo. workdir ( ) . unwrap_or_else ( || repo. path ( ) ) ;
280
274
GitCheckout {
281
- location : path. to_path_buf ( ) ,
275
+ path : path. to_path_buf ( ) ,
282
276
database,
283
277
revision,
284
278
repo,
285
279
}
286
280
}
287
281
282
+ /// Gets the remote repository URL.
283
+ fn remote_url ( & self ) -> & Url {
284
+ & self . database . remote . url ( )
285
+ }
286
+
288
287
/// Clone a repo for a `revision` into a local path from a `datatabase`.
289
288
/// This is a filesystem-to-filesystem clone.
290
289
fn clone_into (
@@ -340,7 +339,7 @@ impl<'a> GitCheckout<'a> {
340
339
} ) ?;
341
340
let repo = repo. unwrap ( ) ;
342
341
343
- let checkout = GitCheckout :: new ( into , database, revision, repo) ;
342
+ let checkout = GitCheckout :: new ( database, revision, repo) ;
344
343
checkout. reset ( config) ?;
345
344
Ok ( checkout)
346
345
}
@@ -350,24 +349,28 @@ impl<'a> GitCheckout<'a> {
350
349
match self . repo . revparse_single ( "HEAD" ) {
351
350
Ok ( ref head) if head. id ( ) == self . revision => {
352
351
// See comments in reset() for why we check this
353
- self . location . join ( ".cargo-ok" ) . exists ( )
352
+ self . path . join ( CHECKOUT_READY_LOCK ) . exists ( )
354
353
}
355
354
_ => false ,
356
355
}
357
356
}
358
357
359
- /// `git reset --hard` to the revision of this checkout, with additional
360
- /// interrupt protection by a dummy `.cargo-ok` file.
358
+ /// Similar to [`reset()`]. This roughly performs `git reset --hard` to the
359
+ /// revision of this checkout, with additional interrupt protection by a
360
+ /// dummy file [`CHECKOUT_READY_LOCK`].
361
+ ///
362
+ /// If we're interrupted while performing a `git reset` (e.g., we die
363
+ /// because of a signal) Cargo needs to be sure to try to check out this
364
+ /// repo again on the next go-round.
365
+ ///
366
+ /// To enable this we have a dummy file in our checkout, [`.cargo-ok`],
367
+ /// which if present means that the repo has been successfully reset and is
368
+ /// ready to go. Hence if we start to do a reset, we make sure this file
369
+ /// *doesn't* exist, and then once we're done we create the file.
370
+ ///
371
+ /// [`.cargo-ok`]: CHECKOUT_READY_LOCK
361
372
fn reset ( & self , config : & Config ) -> CargoResult < ( ) > {
362
- // If we're interrupted while performing this reset (e.g., we die because
363
- // of a signal) Cargo needs to be sure to try to check out this repo
364
- // again on the next go-round.
365
- //
366
- // To enable this we have a dummy file in our checkout, .cargo-ok, which
367
- // if present means that the repo has been successfully reset and is
368
- // ready to go. Hence if we start to do a reset, we make sure this file
369
- // *doesn't* exist, and then once we're done we create the file.
370
- let ok_file = self . location . join ( ".cargo-ok" ) ;
373
+ let ok_file = self . path . join ( CHECKOUT_READY_LOCK ) ;
371
374
let _ = paths:: remove_file ( & ok_file) ;
372
375
info ! ( "reset {} to {}" , self . repo. path( ) . display( ) , self . revision) ;
373
376
@@ -388,8 +391,8 @@ impl<'a> GitCheckout<'a> {
388
391
/// Submodules set to `none` won't be fetched.
389
392
///
390
393
/// [^1]: <https://git-scm.com/docs/git-submodule#Documentation/git-submodule.txt-none>
391
- fn update_submodules ( & self , cargo_config : & Config , parent_remote_url : & Url ) -> CargoResult < ( ) > {
392
- return update_submodules ( & self . repo , cargo_config, parent_remote_url ) ;
394
+ fn update_submodules ( & self , cargo_config : & Config ) -> CargoResult < ( ) > {
395
+ return update_submodules ( & self . repo , cargo_config, self . remote_url ( ) ) ;
393
396
394
397
/// Recusive helper for [`GitCheckout::update_submodules`].
395
398
fn update_submodules (
@@ -892,13 +895,15 @@ pub fn with_fetch_options(
892
895
/// * Turns [`GitReference`] into refspecs accordingly.
893
896
/// * Dispatches `git fetch` using libgit2, gitoxide, or git CLI.
894
897
///
895
- /// `remote_kind` is a thing for [`-Zgitoxide`] shallow clones at this time.
896
- /// It could be extended when libgit2 supports shallow clones.
898
+ /// The `remote_url` argument is the git remote URL where we want to fetch from.
899
+ ///
900
+ /// The `remote_kind` argument is a thing for [`-Zgitoxide`] shallow clones
901
+ /// at this time. It could be extended when libgit2 supports shallow clones.
897
902
///
898
903
/// [`-Zgitoxide`]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#gitoxide
899
904
pub fn fetch (
900
905
repo : & mut git2:: Repository ,
901
- orig_url : & str ,
906
+ remote_url : & str ,
902
907
reference : & GitReference ,
903
908
config : & Config ,
904
909
remote_kind : RemoteKind ,
@@ -915,7 +920,7 @@ pub fn fetch(
915
920
916
921
let shallow = remote_kind. to_shallow_setting ( repo. is_shallow ( ) , config) ;
917
922
918
- let oid_to_fetch = match github_fast_path ( repo, orig_url , reference, config) {
923
+ let oid_to_fetch = match github_fast_path ( repo, remote_url , reference, config) {
919
924
Ok ( FastPathRev :: UpToDate ) => return Ok ( ( ) ) ,
920
925
Ok ( FastPathRev :: NeedsFetch ( rev) ) => Some ( rev) ,
921
926
Ok ( FastPathRev :: Indeterminate ) => None ,
@@ -978,7 +983,7 @@ pub fn fetch(
978
983
}
979
984
980
985
if let Some ( true ) = config. net_config ( ) ?. git_fetch_with_cli {
981
- return fetch_with_cli ( repo, orig_url , & refspecs, tags, config) ;
986
+ return fetch_with_cli ( repo, remote_url , & refspecs, tags, config) ;
982
987
}
983
988
984
989
if config
@@ -1014,10 +1019,10 @@ pub fn fetch(
1014
1019
)
1015
1020
. map_err ( crate :: sources:: git:: fetch:: Error :: from)
1016
1021
. and_then ( |repo| {
1017
- debug ! ( "initiating fetch of {:?} from {}" , refspecs , orig_url ) ;
1022
+ debug ! ( "initiating fetch of {refspecs :?} from {remote_url}" ) ;
1018
1023
let url_for_authentication = & mut * url_for_authentication;
1019
1024
let remote = repo
1020
- . remote_at ( orig_url ) ?
1025
+ . remote_at ( remote_url ) ?
1021
1026
. with_fetch_tags ( if tags {
1022
1027
gix:: remote:: fetch:: Tags :: All
1023
1028
} else {
@@ -1036,10 +1041,9 @@ pub fn fetch(
1036
1041
let mut authenticate = connection. configured_credentials ( url) ?;
1037
1042
let connection = connection. with_credentials (
1038
1043
move |action : gix:: protocol:: credentials:: helper:: Action | {
1039
- if let Some ( url) = action
1040
- . context ( )
1041
- . and_then ( |ctx| ctx. url . as_ref ( ) . filter ( |url| * url != orig_url) )
1042
- {
1044
+ if let Some ( url) = action. context ( ) . and_then ( |ctx| {
1045
+ ctx. url . as_ref ( ) . filter ( |url| * url != remote_url)
1046
+ } ) {
1043
1047
url_for_authentication ( url. as_ref ( ) ) ;
1044
1048
}
1045
1049
authenticate ( action)
@@ -1085,9 +1089,9 @@ pub fn fetch(
1085
1089
}
1086
1090
res
1087
1091
} else {
1088
- debug ! ( "doing a fetch for {}" , orig_url ) ;
1092
+ debug ! ( "doing a fetch for {remote_url}" ) ;
1089
1093
let git_config = git2:: Config :: open_default ( ) ?;
1090
- with_fetch_options ( & git_config, orig_url , config, & mut |mut opts| {
1094
+ with_fetch_options ( & git_config, remote_url , config, & mut |mut opts| {
1091
1095
if tags {
1092
1096
opts. download_tags ( git2:: AutotagOption :: All ) ;
1093
1097
}
@@ -1103,10 +1107,10 @@ pub fn fetch(
1103
1107
// blown away the repository, then we want to return the error as-is.
1104
1108
let mut repo_reinitialized = false ;
1105
1109
loop {
1106
- debug ! ( "initiating fetch of {:?} from {}" , refspecs , orig_url ) ;
1107
- let res = repo
1108
- . remote_anonymous ( orig_url ) ?
1109
- . fetch ( & refspecs, Some ( & mut opts) , None ) ;
1110
+ debug ! ( "initiating fetch of {refspecs :?} from {remote_url}" ) ;
1111
+ let res =
1112
+ repo . remote_anonymous ( remote_url ) ?
1113
+ . fetch ( & refspecs, Some ( & mut opts) , None ) ;
1110
1114
let err = match res {
1111
1115
Ok ( ( ) ) => break ,
1112
1116
Err ( e) => e,
0 commit comments