Skip to content

Commit 8fc3da5

Browse files
committed
Auto merge of #8409 - alexcrichton:git-instead-of, r=Eh2406
Improve git error messages a bit This commit is targeted at further improving the error messages generated from git errors. For authentication errors the actual URL fetched is now printed out as well if it's different from the original URL. This should help handle `insteadOf` logic where SSH urls are used instead of HTTPS urls and users can know to track that down. Otherwise the logic about recommending `net.git-fetch-with-cli` was tweaked a bit and moved to the same location as the rest of our error reporting. Note that a change piggy-backed here as well is that `Caused by:` errors are now automatically all tabbed over a bit instead of only having the first line tabbed over. This required a good number of tests to be updated, but it's just an updated in renderings.
2 parents 3b142db + 6514c28 commit 8fc3da5

23 files changed

+216
-131
lines changed

src/cargo/core/resolver/errors.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,8 @@ pub(super) fn activation_error(
219219
};
220220

221221
let mut msg = format!(
222-
"failed to select a version for the requirement `{} = \"{}\"`\n \
223-
candidate versions found which didn't match: {}\n \
222+
"failed to select a version for the requirement `{} = \"{}\"`\n\
223+
candidate versions found which didn't match: {}\n\
224224
location searched: {}\n",
225225
dep.package_name(),
226226
dep.version_req(),

src/cargo/lib.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,13 @@ fn _display_error(err: &Error, shell: &mut Shell, as_err: bool) -> bool {
163163
return true;
164164
}
165165
drop(writeln!(shell.err(), "\nCaused by:"));
166-
drop(writeln!(shell.err(), " {}", cause));
166+
for line in cause.to_string().lines() {
167+
if line.is_empty() {
168+
drop(writeln!(shell.err(), ""));
169+
} else {
170+
drop(writeln!(shell.err(), " {}", line));
171+
}
172+
}
167173
}
168174
false
169175
}

src/cargo/sources/git/utils.rs

+56-48
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::util::errors::{CargoResult, CargoResultExt};
33
use crate::util::paths;
44
use crate::util::process_builder::process;
55
use crate::util::{network, Config, IntoUrl, Progress};
6-
use anyhow::anyhow;
6+
use anyhow::{anyhow, Context};
77
use curl::easy::List;
88
use git2::{self, ErrorClass, ObjectType};
99
use log::{debug, info};
@@ -85,46 +85,13 @@ impl GitRemote {
8585
locked_rev: Option<git2::Oid>,
8686
cargo_config: &Config,
8787
) -> CargoResult<(GitDatabase, git2::Oid)> {
88-
let format_error = |e: anyhow::Error, operation| {
89-
let may_be_libgit_fault = e
90-
.chain()
91-
.filter_map(|e| e.downcast_ref::<git2::Error>())
92-
.any(|e| match e.class() {
93-
ErrorClass::Net
94-
| ErrorClass::Ssl
95-
| ErrorClass::Submodule
96-
| ErrorClass::FetchHead
97-
| ErrorClass::Ssh
98-
| ErrorClass::Callback
99-
| ErrorClass::Http => true,
100-
_ => false,
101-
});
102-
let uses_cli = cargo_config
103-
.net_config()
104-
.ok()
105-
.and_then(|config| config.git_fetch_with_cli)
106-
.unwrap_or(false);
107-
let msg = if !uses_cli && may_be_libgit_fault {
108-
format!(
109-
r"failed to {} into: {}
110-
If your environment requires git authentication or proxying, try enabling `git-fetch-with-cli`
111-
https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli",
112-
operation,
113-
into.display()
114-
)
115-
} else {
116-
format!("failed to {} into: {}", operation, into.display())
117-
};
118-
e.context(msg)
119-
};
120-
12188
// If we have a previous instance of `GitDatabase` then fetch into that
12289
// if we can. If that can successfully load our revision then we've
12390
// populated the database with the latest version of `reference`, so
12491
// return that database and the rev we resolve to.
12592
if let Some(mut db) = db {
12693
fetch(&mut db.repo, self.url.as_str(), reference, cargo_config)
127-
.map_err(|e| format_error(e, "fetch"))?;
94+
.context(format!("failed to fetch into: {}", into.display()))?;
12895
match locked_rev {
12996
Some(rev) => {
13097
if db.contains(rev) {
@@ -148,7 +115,7 @@ impl GitRemote {
148115
paths::create_dir_all(into)?;
149116
let mut repo = init(into, true)?;
150117
fetch(&mut repo, self.url.as_str(), reference, cargo_config)
151-
.map_err(|e| format_error(e, "clone"))?;
118+
.context(format!("failed to clone into: {}", into.display()))?;
152119
let rev = match locked_rev {
153120
Some(rev) => rev,
154121
None => reference.resolve(&repo)?,
@@ -481,9 +448,14 @@ where
481448
let mut ssh_agent_attempts = Vec::new();
482449
let mut any_attempts = false;
483450
let mut tried_sshkey = false;
451+
let mut url_attempt = None;
484452

453+
let orig_url = url;
485454
let mut res = f(&mut |url, username, allowed| {
486455
any_attempts = true;
456+
if url != orig_url {
457+
url_attempt = Some(url.to_string());
458+
}
487459
// libgit2's "USERNAME" authentication actually means that it's just
488460
// asking us for a username to keep going. This is currently only really
489461
// used for SSH authentication and isn't really an authentication type.
@@ -615,47 +587,83 @@ where
615587
}
616588
}
617589
}
618-
619-
if res.is_ok() || !any_attempts {
620-
return res.map_err(From::from);
621-
}
590+
let mut err = match res {
591+
Ok(e) => return Ok(e),
592+
Err(e) => e,
593+
};
622594

623595
// In the case of an authentication failure (where we tried something) then
624596
// we try to give a more helpful error message about precisely what we
625597
// tried.
626-
let res = res.map_err(anyhow::Error::from).chain_err(|| {
598+
if any_attempts {
627599
let mut msg = "failed to authenticate when downloading \
628600
repository"
629601
.to_string();
602+
603+
if let Some(attempt) = &url_attempt {
604+
if url != attempt {
605+
msg.push_str(": ");
606+
msg.push_str(attempt);
607+
}
608+
}
609+
msg.push_str("\n");
630610
if !ssh_agent_attempts.is_empty() {
631611
let names = ssh_agent_attempts
632612
.iter()
633613
.map(|s| format!("`{}`", s))
634614
.collect::<Vec<_>>()
635615
.join(", ");
636616
msg.push_str(&format!(
637-
"\nattempted ssh-agent authentication, but \
638-
none of the usernames {} succeeded",
617+
"\n* attempted ssh-agent authentication, but \
618+
no usernames succeeded: {}",
639619
names
640620
));
641621
}
642622
if let Some(failed_cred_helper) = cred_helper_bad {
643623
if failed_cred_helper {
644624
msg.push_str(
645-
"\nattempted to find username/password via \
625+
"\n* attempted to find username/password via \
646626
git's `credential.helper` support, but failed",
647627
);
648628
} else {
649629
msg.push_str(
650-
"\nattempted to find username/password via \
630+
"\n* attempted to find username/password via \
651631
`credential.helper`, but maybe the found \
652632
credentials were incorrect",
653633
);
654634
}
655635
}
656-
msg
657-
})?;
658-
Ok(res)
636+
msg.push_str("\n\n");
637+
msg.push_str("if the git CLI succeeds then `net.git-fetch-with-cli` may help here\n");
638+
msg.push_str("https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli");
639+
err = err.context(msg);
640+
641+
// Otherwise if we didn't even get to the authentication phase them we may
642+
// have failed to set up a connection, in these cases hint on the
643+
// `net.git-fetch-with-cli` configuration option.
644+
} else if let Some(e) = err.downcast_ref::<git2::Error>() {
645+
match e.class() {
646+
ErrorClass::Net
647+
| ErrorClass::Ssl
648+
| ErrorClass::Submodule
649+
| ErrorClass::FetchHead
650+
| ErrorClass::Ssh
651+
| ErrorClass::Callback
652+
| ErrorClass::Http => {
653+
let mut msg = "network failure seems to have happened\n".to_string();
654+
msg.push_str(
655+
"if a proxy or similar is necessary `net.git-fetch-with-cli` may help here\n",
656+
);
657+
msg.push_str(
658+
"https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli",
659+
);
660+
err = err.context(msg);
661+
}
662+
_ => {}
663+
}
664+
}
665+
666+
Err(err)
659667
}
660668

661669
fn reset(repo: &git2::Repository, obj: &git2::Object<'_>, config: &Config) -> CargoResult<()> {

src/cargo/util/network.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ impl<'a> Retry<'a> {
2020
match f() {
2121
Err(ref e) if maybe_spurious(e) && self.remaining > 0 => {
2222
let msg = format!(
23-
"spurious network error ({} tries \
24-
remaining): {}",
25-
self.remaining, e
23+
"spurious network error ({} tries remaining): {}",
24+
self.remaining,
25+
e.root_cause(),
2626
);
2727
self.config.shell().warn(msg)?;
2828
self.remaining -= 1;

src/cargo/util/toml/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ fn do_read_manifest(
8181
add_unused(manifest.warnings_mut());
8282
if manifest.targets().iter().all(|t| t.is_custom_build()) {
8383
bail!(
84-
"no targets specified in the manifest\n \
84+
"no targets specified in the manifest\n\
8585
either src/lib.rs, src/main.rs, a [lib] section, or \
8686
[[bin]] section must be present"
8787
)

tests/testsuite/bad_config.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1398,8 +1398,8 @@ Caused by:
13981398
13991399
Caused by:
14001400
invalid configuration for key `target.cfg(not(target_os = \"none\")).runner`
1401-
expected a string or array of strings, but found a boolean for \
1402-
`target.cfg(not(target_os = \"none\")).runner` in [..]/foo/.cargo/config
1401+
expected a string or array of strings, but found a boolean for \
1402+
`target.cfg(not(target_os = \"none\")).runner` in [..]/foo/.cargo/config
14031403
",
14041404
)
14051405
.run();

tests/testsuite/cargo_features.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Caused by:
3030
Caused by:
3131
feature `test-dummy-unstable` is required
3232
33-
consider adding `cargo-features = [\"test-dummy-unstable\"]` to the manifest
33+
consider adding `cargo-features = [\"test-dummy-unstable\"]` to the manifest
3434
",
3535
)
3636
.run();
@@ -47,9 +47,9 @@ Caused by:
4747
Caused by:
4848
feature `test-dummy-unstable` is required
4949
50-
this Cargo does not support nightly features, but if you
51-
switch to nightly channel you can add
52-
`cargo-features = [\"test-dummy-unstable\"]` to enable this feature
50+
this Cargo does not support nightly features, but if you
51+
switch to nightly channel you can add
52+
`cargo-features = [\"test-dummy-unstable\"]` to enable this feature
5353
",
5454
)
5555
.run();
@@ -148,7 +148,7 @@ error: failed to parse manifest at `[..]`
148148
Caused by:
149149
the cargo feature `test-dummy-unstable` requires a nightly version of Cargo, \
150150
but this is the `stable` channel
151-
See [..]
151+
See [..]
152152
",
153153
)
154154
.run();
@@ -213,7 +213,7 @@ Caused by:
213213
Caused by:
214214
the cargo feature `test-dummy-unstable` requires a nightly version of Cargo, \
215215
but this is the `stable` channel
216-
See [..]
216+
See [..]
217217
",
218218
)
219219
.run();
@@ -255,7 +255,7 @@ error: failed to parse manifest at `[..]`
255255
Caused by:
256256
the cargo feature `test-dummy-unstable` requires a nightly version of Cargo, \
257257
but this is the `stable` channel
258-
See [..]
258+
See [..]
259259
",
260260
)
261261
.run();

tests/testsuite/directory.rs

+8-9
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,9 @@ error: failed to compile `bar v0.1.0`, intermediate artifacts can be found at `[
192192
193193
Caused by:
194194
no matching package named `baz` found
195-
location searched: registry `https://github.com/rust-lang/crates.io-index`
196-
perhaps you meant: bar or foo
197-
required by package `bar v0.1.0`
195+
location searched: registry `https://github.com/rust-lang/crates.io-index`
196+
perhaps you meant: bar or foo
197+
required by package `bar v0.1.0`
198198
",
199199
)
200200
.run();
@@ -663,11 +663,10 @@ Caused by:
663663
664664
Caused by:
665665
the source my-git-repo requires a lock file to be present first before it can be
666-
used against vendored source code
667-
668-
remove the source replacement configuration, generate a lock file, and then
669-
restore the source replacement configuration to continue the build
666+
used against vendored source code
670667
668+
remove the source replacement configuration, generate a lock file, and then
669+
restore the source replacement configuration to continue the build
671670
",
672671
)
673672
.run();
@@ -765,8 +764,8 @@ Caused by:
765764
failed to select a version for the requirement `foo = \"^2\"`
766765
candidate versions found which didn't match: 0.0.1
767766
location searched: directory source `[..] (which is replacing registry `[..]`)
768-
required by package `bar v0.1.0`
769-
perhaps a crate was updated and forgotten to be re-vendored?
767+
required by package `bar v0.1.0`
768+
perhaps a crate was updated and forgotten to be re-vendored?
770769
",
771770
)
772771
.with_status(101)

tests/testsuite/features.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ fn invalid3() {
9898
9999
Caused by:
100100
Feature `bar` depends on `baz` which is not an optional dependency.
101-
Consider adding `optional = true` to the dependency
101+
Consider adding `optional = true` to the dependency
102102
",
103103
)
104104
.run();
@@ -1456,7 +1456,7 @@ fn namespaced_non_optional_dependency() {
14561456
14571457
Caused by:
14581458
Feature `bar` includes `crate:baz` which is not an optional dependency.
1459-
Consider adding `optional = true` to the dependency
1459+
Consider adding `optional = true` to the dependency
14601460
",
14611461
)
14621462
.run();
@@ -1519,7 +1519,7 @@ fn namespaced_shadowed_dep() {
15191519
15201520
Caused by:
15211521
Feature `baz` includes the optional dependency of the same name, but this is left implicit in the features included by this feature.
1522-
Consider adding `crate:baz` to this feature's requirements.
1522+
Consider adding `crate:baz` to this feature's requirements.
15231523
",
15241524
)
15251525
.run();
@@ -1555,8 +1555,8 @@ fn namespaced_shadowed_non_optional() {
15551555
15561556
Caused by:
15571557
Feature `baz` includes the dependency of the same name, but this is left implicit in the features included by this feature.
1558-
Additionally, the dependency must be marked as optional to be included in the feature definition.
1559-
Consider adding `crate:baz` to this feature's requirements and marking the dependency as `optional = true`
1558+
Additionally, the dependency must be marked as optional to be included in the feature definition.
1559+
Consider adding `crate:baz` to this feature's requirements and marking the dependency as `optional = true`
15601560
",
15611561
)
15621562
.run();
@@ -1592,7 +1592,7 @@ fn namespaced_implicit_non_optional() {
15921592
15931593
Caused by:
15941594
Feature `bar` includes `baz` which is not defined as a feature.
1595-
A non-optional dependency of the same name is defined; consider adding `optional = true` to its definition
1595+
A non-optional dependency of the same name is defined; consider adding `optional = true` to its definition
15961596
",
15971597
).run(
15981598
);

tests/testsuite/features2.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1318,7 +1318,7 @@ error: failed to parse manifest at `[..]/foo/Cargo.toml`
13181318
Caused by:
13191319
feature `resolver` is required
13201320
1321-
consider adding `cargo-features = [\"resolver\"]` to the manifest
1321+
consider adding `cargo-features = [\"resolver\"]` to the manifest
13221322
",
13231323
)
13241324
.run();
@@ -1347,7 +1347,7 @@ error: failed to parse manifest at `[..]/foo/Cargo.toml`
13471347
Caused by:
13481348
feature `resolver` is required
13491349
1350-
consider adding `cargo-features = [\"resolver\"]` to the manifest
1350+
consider adding `cargo-features = [\"resolver\"]` to the manifest
13511351
",
13521352
)
13531353
.run();

0 commit comments

Comments
 (0)