diff --git a/src/sources/git/utils.rs b/src/sources/git/utils.rs index ee20d194ae6..0c9b04977d6 100644 --- a/src/sources/git/utils.rs +++ b/src/sources/git/utils.rs @@ -882,6 +882,7 @@ where /// `git reset --hard` to the given `obj` for the `repo`. /// /// The `obj` is a commit-ish to which the head should be moved. +#[tracing::instrument(skip_all)] fn reset(repo: &git2::Repository, obj: &git2::Object<'_>, gctx: &GlobalContext) -> CargoResult<()> { let mut pb = Progress::new("Checkout", gctx); let mut opts = git2::build::CheckoutBuilder::new(); @@ -1006,6 +1007,7 @@ pub fn with_fetch_options( /// at this time. It could be extended when libgit2 supports shallow clones. /// /// [`-Zgitoxide`]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#gitoxide +#[tracing::instrument(skip_all)] pub fn fetch( repo: &mut git2::Repository, remote_url: &str, @@ -1136,6 +1138,7 @@ fn has_shallow_lock_file(err: &crate::sources::git::fetch::Error) -> bool { /// speed and portability of using `libgit2`. /// /// [1]: https://doc.rust-lang.org/nightly/cargo/reference/config.html#netgit-fetch-with-cli +#[tracing::instrument(skip(repo, gctx))] fn fetch_with_cli( repo: &mut git2::Repository, url: &str, @@ -1194,13 +1197,21 @@ fn fetch_with_cli( gctx.shell() .verbose(|s| s.status("Running", &cmd.to_string()))?; network::retry::with_retry(gctx, || { - cmd.exec() - .map_err(|error| GitCliError::new(error, true).into()) + cmd.exec().map_err(|error| { + GitCliError::new(error) + .spurious(true) + .workaround( + "help: re-try with `net.git-fetch-with-cli = false` to see if it resolves the problem +https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli", + ) + .into() + }) })?; Ok(()) } +#[tracing::instrument(skip(repo, gctx))] fn fetch_with_gitoxide( repo: &mut git2::Repository, remote_url: &str, @@ -1312,6 +1323,7 @@ fn fetch_with_gitoxide( res } +#[tracing::instrument(skip(repo, gctx))] fn fetch_with_libgit2( repo: &mut git2::Repository, remote_url: &str, @@ -1563,6 +1575,7 @@ enum FastPathRev { /// this function and move forward on the normal path. /// /// [^1]: +#[tracing::instrument(skip(repo, gctx))] fn github_fast_path( repo: &mut git2::Repository, url: &str, diff --git a/src/util/errors.rs b/src/util/errors.rs index 69c2ba6c25c..3f15392f64d 100644 --- a/src/util/errors.rs +++ b/src/util/errors.rs @@ -375,11 +375,26 @@ pub type GitCliResult = Result<(), GitCliError>; pub struct GitCliError { inner: Error, is_spurious: bool, + workaround: Option<&'static str>, } impl GitCliError { - pub fn new(inner: Error, is_spurious: bool) -> GitCliError { - GitCliError { inner, is_spurious } + pub fn new(inner: Error) -> GitCliError { + GitCliError { + inner, + is_spurious: false, + workaround: None, + } + } + + pub fn workaround(mut self, workaround: &'static str) -> Self { + self.workaround = Some(workaround); + self + } + + pub fn spurious(mut self, yes: bool) -> Self { + self.is_spurious = yes; + self } pub fn is_spurious(&self) -> bool { @@ -395,7 +410,13 @@ impl std::error::Error for GitCliError { impl fmt::Display for GitCliError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.inner.fmt(f) + self.inner.fmt(f)?; + if let Some(workaround) = self.workaround { + writeln!(f)?; + writeln!(f)?; + write!(f, "{workaround}")?; + } + Ok(()) } } diff --git a/src/util/network/retry.rs b/src/util/network/retry.rs index 2dfe117ecb9..839bbfa4dfd 100644 --- a/src/util/network/retry.rs +++ b/src/util/network/retry.rs @@ -422,9 +422,9 @@ fn retry_after_parsing() { #[test] fn git_cli_error_spurious() { - let error = GitCliError::new(Error::msg("test-git-cli-error"), false); + let error = GitCliError::new(Error::msg("test-git-cli-error")).spurious(false); assert!(!maybe_spurious(&error.into())); - let error = GitCliError::new(Error::msg("test-git-cli-error"), true); + let error = GitCliError::new(Error::msg("test-git-cli-error")).spurious(true); assert!(maybe_spurious(&error.into())); } diff --git a/tests/testsuite/git.rs b/tests/testsuite/git.rs index d90ecc97dcf..5578ea43fc9 100644 --- a/tests/testsuite/git.rs +++ b/tests/testsuite/git.rs @@ -3275,6 +3275,71 @@ fn git_fetch_cli_env_clean() { .run(); } +#[cargo_test(requires = "git")] +fn git_fetch_cli_error_suggests_libgit2() { + let git_dep = git::new("dep1", |project| { + project + .file("Cargo.toml", &basic_manifest("dep1", "0.5.0")) + .file("src/lib.rs", "") + }); + + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + edition = "2015" + + [dependencies] + dep1 = {{ git = '{}/missing' }} + "#, + git_dep.url() + ), + ) + .file("src/lib.rs", "") + .file( + ".cargo/config.toml", + r#" + [net] + git-fetch-with-cli = true + retry = 0 + "#, + ) + .build(); + + p.cargo("fetch") + .with_status(101) + .with_stderr_data(str![[r#" +[UPDATING] git repository `[ROOTURL]/dep1/missing` +fatal: '[ROOT]/dep1/missing' does not appear to be a git repository +fatal: Could not read from remote repository. + +Please make sure you have the correct access rights +and the repository exists. +[ERROR] failed to get `dep1` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` + +Caused by: + failed to load source for dependency `dep1` + +Caused by: + unable to update [ROOTURL]/dep1/missing + +Caused by: + failed to clone into: [ROOT]/home/.cargo/git/db/missing-[HASH] + +Caused by: + process didn't exit successfully: `git fetch [..]` ([EXIT_STATUS]: 128) + + [HELP] re-try with `net.git-fetch-with-cli = false` to see if it resolves the problem + https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli + +"#]]) + .run(); +} + #[cargo_test] fn dirty_submodule() { // `cargo package` warns for dirty file in submodule. @@ -4238,10 +4303,19 @@ fn github_fastpath_error_message() { [UPDATING] git repository `https://github.com/rust-lang/bitflags.git` fatal: remote [ERROR] upload-pack: not our ref 11111b376b93484341c68fbca3ca110ae5cd2790 [WARNING] spurious network error (3 tries remaining): process didn't exit successfully: `git fetch --no-tags --quiet --force --update-head-ok [..] + +[HELP] re-try with `net.git-fetch-with-cli = false` to see if it resolves the problem +https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli fatal: remote [ERROR] upload-pack: not our ref 11111b376b93484341c68fbca3ca110ae5cd2790 [WARNING] spurious network error (2 tries remaining): process didn't exit successfully: `git fetch --no-tags --quiet --force --update-head-ok [..] + +[HELP] re-try with `net.git-fetch-with-cli = false` to see if it resolves the problem +https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli fatal: remote [ERROR] upload-pack: not our ref 11111b376b93484341c68fbca3ca110ae5cd2790 [WARNING] spurious network error (1 try remaining): process didn't exit successfully: `git fetch --no-tags --quiet --force --update-head-ok [..] + +[HELP] re-try with `net.git-fetch-with-cli = false` to see if it resolves the problem +https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli fatal: remote [ERROR] upload-pack: not our ref 11111b376b93484341c68fbca3ca110ae5cd2790 [ERROR] failed to get `bitflags` as a dependency of package `foo v0.1.0 ([ROOT]/foo)` @@ -4260,6 +4334,9 @@ Caused by: Caused by: process didn't exit successfully: `git fetch --no-tags --quiet --force --update-head-ok [..] + [HELP] re-try with `net.git-fetch-with-cli = false` to see if it resolves the problem + https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli + "#]]) .run(); }