@@ -23,6 +23,10 @@ use std::sync::atomic::{AtomicBool, Ordering};
2323use std:: time:: { Duration , Instant } ;
2424use url:: Url ;
2525
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+
2630fn serialize_str < T , S > ( t : & T , s : S ) -> Result < S :: Ok , S :: Error >
2731where
2832 T : fmt:: Display ,
@@ -53,29 +57,24 @@ pub struct GitRemote {
5357
5458/// A local clone of a remote repository's database. Multiple [`GitCheckout`]s
5559/// can be cloned from a single [`GitDatabase`].
56- #[ derive( Serialize ) ]
5760pub struct GitDatabase {
5861 /// The remote repository where this database is fetched from.
5962 remote : GitRemote ,
6063 /// Path to the root of the underlying Git repository on the local filesystem.
6164 path : PathBuf ,
6265 /// Underlying Git repository instance for this database.
63- #[ serde( skip_serializing) ]
6466 repo : git2:: Repository ,
6567}
6668
6769/// A local checkout of a particular revision from a [`GitDatabase`].
68- #[ derive( Serialize ) ]
6970pub struct GitCheckout < ' a > {
7071 /// The git database where this checkout is cloned from.
7172 database : & ' a GitDatabase ,
7273 /// Path to the root of the underlying Git repository on the local filesystem.
73- location : PathBuf ,
74+ path : PathBuf ,
7475 /// The git revision this checkout is for.
75- #[ serde( serialize_with = "serialize_str" ) ]
7676 revision : git2:: Oid ,
7777 /// Underlying Git repository instance for this checkout.
78- #[ serde( skip_serializing) ]
7978 repo : git2:: Repository ,
8079}
8180
@@ -90,10 +89,6 @@ impl GitRemote {
9089 & self . url
9190 }
9291
93- pub fn rev_for ( & self , path : & Path , reference : & GitReference ) -> CargoResult < git2:: Oid > {
94- reference. resolve ( & self . db_at ( path) ?. repo )
95- }
96-
9792 /// Fetches and checkouts to a reference or a revision from this remote
9893 /// into a local path.
9994 ///
@@ -184,21 +179,20 @@ impl GitDatabase {
184179 rev : git2:: Oid ,
185180 dest : & Path ,
186181 cargo_config : & Config ,
187- parent_remote_url : & Url ,
188182 ) -> CargoResult < GitCheckout < ' _ > > {
189183 // If the existing checkout exists, and it is fresh, use it.
190184 // A non-fresh checkout can happen if the checkout operation was
191185 // interrupted. In that case, the checkout gets deleted and a new
192186 // clone is created.
193187 let checkout = match git2:: Repository :: open ( dest)
194188 . ok ( )
195- . map ( |repo| GitCheckout :: new ( dest , self , rev, repo) )
189+ . map ( |repo| GitCheckout :: new ( self , rev, repo) )
196190 . filter ( |co| co. is_fresh ( ) )
197191 {
198192 Some ( co) => co,
199193 None => GitCheckout :: clone_into ( dest, self , rev, cargo_config) ?,
200194 } ;
201- checkout. update_submodules ( cargo_config, parent_remote_url ) ?;
195+ checkout. update_submodules ( cargo_config) ?;
202196 Ok ( checkout)
203197 }
204198
@@ -270,21 +264,26 @@ impl<'a> GitCheckout<'a> {
270264 /// is done. Use [`GitCheckout::is_fresh`] to check.
271265 ///
272266 /// * 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.
274268 fn new (
275- path : & Path ,
276269 database : & ' a GitDatabase ,
277270 revision : git2:: Oid ,
278271 repo : git2:: Repository ,
279272 ) -> GitCheckout < ' a > {
273+ let path = repo. workdir ( ) . unwrap_or_else ( || repo. path ( ) ) ;
280274 GitCheckout {
281- location : path. to_path_buf ( ) ,
275+ path : path. to_path_buf ( ) ,
282276 database,
283277 revision,
284278 repo,
285279 }
286280 }
287281
282+ /// Gets the remote repository URL.
283+ fn remote_url ( & self ) -> & Url {
284+ & self . database . remote . url ( )
285+ }
286+
288287 /// Clone a repo for a `revision` into a local path from a `datatabase`.
289288 /// This is a filesystem-to-filesystem clone.
290289 fn clone_into (
@@ -340,7 +339,7 @@ impl<'a> GitCheckout<'a> {
340339 } ) ?;
341340 let repo = repo. unwrap ( ) ;
342341
343- let checkout = GitCheckout :: new ( into , database, revision, repo) ;
342+ let checkout = GitCheckout :: new ( database, revision, repo) ;
344343 checkout. reset ( config) ?;
345344 Ok ( checkout)
346345 }
@@ -350,24 +349,28 @@ impl<'a> GitCheckout<'a> {
350349 match self . repo . revparse_single ( "HEAD" ) {
351350 Ok ( ref head) if head. id ( ) == self . revision => {
352351 // See comments in reset() for why we check this
353- self . location . join ( ".cargo-ok" ) . exists ( )
352+ self . path . join ( CHECKOUT_READY_LOCK ) . exists ( )
354353 }
355354 _ => false ,
356355 }
357356 }
358357
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
361372 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 ) ;
371374 let _ = paths:: remove_file ( & ok_file) ;
372375 info ! ( "reset {} to {}" , self . repo. path( ) . display( ) , self . revision) ;
373376
@@ -388,8 +391,8 @@ impl<'a> GitCheckout<'a> {
388391 /// Submodules set to `none` won't be fetched.
389392 ///
390393 /// [^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 ( ) ) ;
393396
394397 /// Recusive helper for [`GitCheckout::update_submodules`].
395398 fn update_submodules (
@@ -892,13 +895,15 @@ pub fn with_fetch_options(
892895/// * Turns [`GitReference`] into refspecs accordingly.
893896/// * Dispatches `git fetch` using libgit2, gitoxide, or git CLI.
894897///
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.
897902///
898903/// [`-Zgitoxide`]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#gitoxide
899904pub fn fetch (
900905 repo : & mut git2:: Repository ,
901- orig_url : & str ,
906+ remote_url : & str ,
902907 reference : & GitReference ,
903908 config : & Config ,
904909 remote_kind : RemoteKind ,
@@ -915,7 +920,7 @@ pub fn fetch(
915920
916921 let shallow = remote_kind. to_shallow_setting ( repo. is_shallow ( ) , config) ;
917922
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) {
919924 Ok ( FastPathRev :: UpToDate ) => return Ok ( ( ) ) ,
920925 Ok ( FastPathRev :: NeedsFetch ( rev) ) => Some ( rev) ,
921926 Ok ( FastPathRev :: Indeterminate ) => None ,
@@ -978,7 +983,7 @@ pub fn fetch(
978983 }
979984
980985 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) ;
982987 }
983988
984989 if config
@@ -1014,10 +1019,10 @@ pub fn fetch(
10141019 )
10151020 . map_err ( crate :: sources:: git:: fetch:: Error :: from)
10161021 . and_then ( |repo| {
1017- debug ! ( "initiating fetch of {:?} from {}" , refspecs , orig_url ) ;
1022+ debug ! ( "initiating fetch of {refspecs :?} from {remote_url}" ) ;
10181023 let url_for_authentication = & mut * url_for_authentication;
10191024 let remote = repo
1020- . remote_at ( orig_url ) ?
1025+ . remote_at ( remote_url ) ?
10211026 . with_fetch_tags ( if tags {
10221027 gix:: remote:: fetch:: Tags :: All
10231028 } else {
@@ -1036,10 +1041,9 @@ pub fn fetch(
10361041 let mut authenticate = connection. configured_credentials ( url) ?;
10371042 let connection = connection. with_credentials (
10381043 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+ } ) {
10431047 url_for_authentication ( url. as_ref ( ) ) ;
10441048 }
10451049 authenticate ( action)
@@ -1085,9 +1089,9 @@ pub fn fetch(
10851089 }
10861090 res
10871091 } else {
1088- debug ! ( "doing a fetch for {}" , orig_url ) ;
1092+ debug ! ( "doing a fetch for {remote_url}" ) ;
10891093 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| {
10911095 if tags {
10921096 opts. download_tags ( git2:: AutotagOption :: All ) ;
10931097 }
@@ -1103,10 +1107,10 @@ pub fn fetch(
11031107 // blown away the repository, then we want to return the error as-is.
11041108 let mut repo_reinitialized = false ;
11051109 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 ) ;
11101114 let err = match res {
11111115 Ok ( ( ) ) => break ,
11121116 Err ( e) => e,
0 commit comments