Skip to content

Rework internal errors. #7896

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/cargo-test-support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1645,6 +1645,7 @@ fn substitute_macros(input: &str) -> String {
("[FINISHED]", " Finished"),
("[ERROR]", "error:"),
("[WARNING]", "warning:"),
("[NOTE]", "note:"),
("[DOCUMENTING]", " Documenting"),
("[FRESH]", " Fresh"),
("[UPDATING]", " Updating"),
Expand All @@ -1666,7 +1667,6 @@ fn substitute_macros(input: &str) -> String {
("[IGNORED]", " Ignored"),
("[INSTALLED]", " Installed"),
("[REPLACED]", " Replaced"),
("[NOTE]", " Note"),
];
let mut result = input.to_owned();
for &(pat, subst) in &macros {
Expand Down
6 changes: 3 additions & 3 deletions src/cargo/core/compiler/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use jobserver::Client;
use crate::core::compiler::{self, compilation, Unit};
use crate::core::PackageId;
use crate::util::errors::{CargoResult, CargoResultExt};
use crate::util::{internal, profile, Config};
use crate::util::{profile, Config};

use super::build_plan::BuildPlan;
use super::custom_build::{self, BuildDeps, BuildScriptOutputs, BuildScripts};
Expand Down Expand Up @@ -313,11 +313,11 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
self.files_mut()
.host
.prepare()
.chain_err(|| internal("couldn't prepare build directories"))?;
.chain_err(|| "couldn't prepare build directories")?;
for target in self.files.as_mut().unwrap().target.values_mut() {
target
.prepare()
.chain_err(|| internal("couldn't prepare build directories"))?;
.chain_err(|| "couldn't prepare build directories")?;
}

self.compilation.host_deps_output = self.files_mut().host.deps().to_path_buf();
Expand Down
8 changes: 2 additions & 6 deletions src/cargo/core/compiler/custom_build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,12 +292,8 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoRes
//
// If we have an old build directory, then just move it into place,
// otherwise create it!
paths::create_dir_all(&script_out_dir).chain_err(|| {
internal(
"failed to create script output directory for \
build command",
)
})?;
paths::create_dir_all(&script_out_dir)
.chain_err(|| "failed to create script output directory for build command")?;

// For all our native lib dependencies, pick up their metadata to pass
// along to this custom build command. We're also careful to augment our
Expand Down
3 changes: 1 addition & 2 deletions src/cargo/core/compiler/job_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ use super::job::{
use super::timings::Timings;
use super::{BuildContext, BuildPlan, CompileMode, Context, Unit};
use crate::core::{PackageId, TargetKind};
use crate::handle_error;
use crate::util;
use crate::util::diagnostic_server::{self, DiagnosticPrinter};
use crate::util::{internal, profile, CargoResult, CargoResultExt, ProcessBuilder};
Expand Down Expand Up @@ -531,7 +530,7 @@ impl<'a, 'cfg> DrainState<'a, 'cfg> {
self.emit_warnings(Some(msg), &unit, cx)?;

if !self.active.is_empty() {
handle_error(&e, &mut *cx.bcx.config.shell());
crate::display_error(&e, &mut *cx.bcx.config.shell());
cx.bcx.config.shell().warn(
"build failed, waiting for other \
jobs to finish...",
Expand Down
11 changes: 5 additions & 6 deletions src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub use crate::core::compiler::unit::{Unit, UnitInterner};
use crate::core::manifest::TargetSourcePath;
use crate::core::profiles::{Lto, PanicStrategy, Profile};
use crate::core::{Edition, Feature, InternedString, PackageId, Target};
use crate::util::errors::{self, CargoResult, CargoResultExt, Internal, ProcessError};
use crate::util::errors::{self, CargoResult, CargoResultExt, ProcessError, VerboseError};
use crate::util::machine_message::Message;
use crate::util::{self, machine_message, ProcessBuilder};
use crate::util::{internal, join_paths, paths, profile};
Expand Down Expand Up @@ -262,15 +262,15 @@ fn rustc<'a, 'cfg>(
}
}

fn internal_if_simple_exit_code(err: Error) -> Error {
fn verbose_if_simple_exit_code(err: Error) -> Error {
// If a signal on unix (`code == None`) or an abnormal termination
// on Windows (codes like `0xC0000409`), don't hide the error details.
match err
.downcast_ref::<ProcessError>()
.as_ref()
.and_then(|perr| perr.exit.and_then(|e| e.code()))
{
Some(n) if errors::is_simple_exit_code(n) => Internal::new(err).into(),
Some(n) if errors::is_simple_exit_code(n) => VerboseError::new(err).into(),
_ => err,
}
}
Expand All @@ -288,7 +288,7 @@ fn rustc<'a, 'cfg>(
&mut |line| on_stdout_line(state, line, package_id, &target),
&mut |line| on_stderr_line(state, line, package_id, &target, &mut output_options),
)
.map_err(internal_if_simple_exit_code)
.map_err(verbose_if_simple_exit_code)
.chain_err(|| format!("could not compile `{}`.", name))?;
}

Expand All @@ -302,8 +302,7 @@ fn rustc<'a, 'cfg>(
.replace(&real_name, &crate_name),
);
if src.exists() && src.file_name() != dst.file_name() {
fs::rename(&src, &dst)
.chain_err(|| internal(format!("could not rename crate {:?}", src)))?;
fs::rename(&src, &dst).chain_err(|| format!("could not rename crate {:?}", src))?;
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/cargo/core/compiler/output_depinfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ fn render_filename<P: AsRef<Path>>(path: P, basedir: Option<&str>) -> CargoResul
};
relpath
.to_str()
.ok_or_else(|| internal("path not utf-8"))
.ok_or_else(|| internal(format!("path `{:?}` not utf-8", relpath)))
.map(|f| f.replace(" ", "\\ "))
}

Expand Down Expand Up @@ -119,7 +119,7 @@ pub fn output_depinfo<'a, 'b>(cx: &mut Context<'a, 'b>, unit: &Unit<'a>) -> Carg
.resolve_path(bcx.config)
.as_os_str()
.to_str()
.ok_or_else(|| internal("build.dep-info-basedir path not utf-8"))?
.ok_or_else(|| anyhow::format_err!("build.dep-info-basedir path not utf-8"))?
.to_string();
Some(basedir_string.as_str())
}
Expand Down
5 changes: 5 additions & 0 deletions src/cargo/core/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@ impl Shell {
}
}

/// Prints a cyan 'note' message.
pub fn note<T: fmt::Display>(&mut self, message: T) -> CargoResult<()> {
self.print(&"note", Some(&message), Cyan, false)
}

/// Updates the verbosity of the shell.
pub fn set_verbosity(&mut self, verbosity: Verbosity) {
self.verbosity = verbosity;
Expand Down
90 changes: 43 additions & 47 deletions src/cargo/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use log::debug;
use serde::ser;
use std::fmt;

pub use crate::util::errors::Internal;
pub use crate::util::errors::{InternalError, VerboseError};
pub use crate::util::{CargoResult, CliError, CliResult, Config};

pub const CARGO_ENV: &str = "CARGO";
Expand Down Expand Up @@ -106,64 +106,60 @@ pub fn exit_with_error(err: CliError, shell: &mut Shell) -> ! {
}
}

let CliError {
error,
exit_code,
unknown,
} = err;
// `exit_code` of 0 means non-fatal error (e.g., docopt version info).
let fatal = exit_code != 0;

let hide = unknown && shell.verbosity() != Verbose;

let CliError { error, exit_code } = err;
if let Some(error) = error {
if hide {
drop(shell.error("An unknown error occurred"))
} else if fatal {
drop(shell.error(&error))
} else {
println!("{}", error);
}

if !handle_cause(&error, shell) || hide {
drop(writeln!(
shell.err(),
"\nTo learn more, run the command again \
with --verbose."
));
}
display_error(&error, shell);
}

std::process::exit(exit_code)
}

pub fn handle_error(err: &Error, shell: &mut Shell) {
debug!("handle_error; err={:?}", err);

let _ignored_result = shell.error(err);
handle_cause(err, shell);
/// Displays an error, and all its causes, to stderr.
pub fn display_error(err: &Error, shell: &mut Shell) {
debug!("display_error; err={:?}", err);
let has_verbose = _display_error(err, shell);
if has_verbose {
drop(writeln!(
shell.err(),
"\nTo learn more, run the command again with --verbose."
));
}
if err
.chain()
.any(|e| e.downcast_ref::<InternalError>().is_some())
{
drop(shell.note("this is an unexpected cargo internal error"));
drop(
shell.note(
"we would appreciate a bug report: https://github.com/rust-lang/cargo/issues/",
),
);
drop(shell.note(format!("{}", version())));
// Once backtraces are stabilized, this should print out a backtrace
// if it is available.
}
}

fn handle_cause(cargo_err: &Error, shell: &mut Shell) -> bool {
fn print(error: &str, shell: &mut Shell) {
drop(writeln!(shell.err(), "\nCaused by:"));
drop(writeln!(shell.err(), " {}", error));
fn _display_error(err: &Error, shell: &mut Shell) -> bool {
let verbosity = shell.verbosity();
let is_verbose = |e: &(dyn std::error::Error + 'static)| -> bool {
verbosity != Verbose && e.downcast_ref::<VerboseError>().is_some()
};
// Generally the top error shouldn't be verbose, but check it anyways.
if is_verbose(err.as_ref()) {
return true;
}

let verbose = shell.verbosity();

// The first error has already been printed to the shell.
for err in cargo_err.chain().skip(1) {
drop(shell.error(&err));
for cause in err.chain().skip(1) {
// If we're not in verbose mode then print remaining errors until one
// marked as `Internal` appears.
if verbose != Verbose && err.downcast_ref::<Internal>().is_some() {
return false;
// marked as `VerboseError` appears.
if is_verbose(cause) {
return true;
}

print(&err.to_string(), shell);
drop(writeln!(shell.err(), "\nCaused by:"));
drop(writeln!(shell.err(), " {}", cause));
}

true
false
}

pub fn version() -> VersionInfo {
Expand Down
2 changes: 1 addition & 1 deletion src/cargo/ops/cargo_install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pub fn install(
) {
Ok(()) => succeeded.push(krate),
Err(e) => {
crate::handle_error(&e, &mut opts.config.shell());
crate::display_error(&e, &mut opts.config.shell());
failed.push(krate)
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/cargo/ops/cargo_new.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,11 @@ pub fn new(opts: &NewOptions, config: &Config) -> CargoResult<()> {
}

pub fn init(opts: &NewOptions, config: &Config) -> CargoResult<()> {
// This is here just as a random location to exercise the internal error handling.
if std::env::var_os("__CARGO_TEST_INTERNAL_ERROR").is_some() {
return Err(crate::util::internal("internal error test"));
}

let path = &opts.path;

if fs::metadata(&path.join("Cargo.toml")).is_ok() {
Expand Down
17 changes: 7 additions & 10 deletions src/cargo/ops/cargo_package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use flate2::{Compression, GzBuilder};
use log::debug;
use serde_json::{self, json};
use tar::{Archive, Builder, EntryType, Header};
use termcolor::Color;

use crate::core::compiler::{BuildConfig, CompileMode, DefaultExecutor, Executor};
use crate::core::resolver::ResolveOpts;
Expand All @@ -27,7 +26,7 @@ use crate::sources::PathSource;
use crate::util::errors::{CargoResult, CargoResultExt};
use crate::util::paths;
use crate::util::toml::TomlManifest;
use crate::util::{self, internal, Config, FileLock};
use crate::util::{self, Config, FileLock};

pub struct PackageOpts<'cfg> {
pub config: &'cfg Config,
Expand Down Expand Up @@ -443,17 +442,15 @@ fn tar(
let orig = Path::new(&path).with_file_name("Cargo.toml.orig");
header.set_path(&orig)?;
header.set_cksum();
ar.append(&header, &mut file).chain_err(|| {
internal(format!("could not archive source file `{}`", relative_str))
})?;
ar.append(&header, &mut file)
.chain_err(|| format!("could not archive source file `{}`", relative_str))?;

let toml = pkg.to_registry_toml(ws.config())?;
add_generated_file(&mut ar, &path, &toml, relative_str)?;
} else {
header.set_cksum();
ar.append(&header, &mut file).chain_err(|| {
internal(format!("could not archive source file `{}`", relative_str))
})?;
ar.append(&header, &mut file)
.chain_err(|| format!("could not archive source file `{}`", relative_str))?;
}
}

Expand Down Expand Up @@ -581,7 +578,7 @@ fn compare_resolve(
"package `{}` added to the packaged Cargo.lock file{}",
pkg_id, extra
);
config.shell().status_with_color("Note", msg, Color::Cyan)?;
config.shell().note(msg)?;
}
Ok(())
}
Expand Down Expand Up @@ -794,6 +791,6 @@ fn add_generated_file<D: Display>(
header.set_size(data.len() as u64);
header.set_cksum();
ar.append(&header, data.as_bytes())
.chain_err(|| internal(format!("could not archive source file `{}`", display)))?;
.chain_err(|| format!("could not archive source file `{}`", display))?;
Ok(())
}
2 changes: 1 addition & 1 deletion src/cargo/ops/cargo_uninstall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub fn uninstall(
match uninstall_one(&root, spec, bins, config) {
Ok(()) => succeeded.push(spec),
Err(e) => {
crate::handle_error(&e, &mut config.shell());
crate::display_error(&e, &mut config.shell());
failed.push(spec)
}
}
Expand Down
12 changes: 6 additions & 6 deletions src/cargo/sources/git/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::core::GitReference;
use crate::util::errors::{CargoResult, CargoResultExt};
use crate::util::paths;
use crate::util::process_builder::process;
use crate::util::{internal, network, Config, IntoUrl, Progress};
use crate::util::{network, Config, IntoUrl, Progress};
use curl::easy::{Easy, List};
use git2::{self, ObjectType};
use log::{debug, info};
Expand Down Expand Up @@ -358,9 +358,9 @@ impl<'a> GitCheckout<'a> {
cargo_config: &Config,
) -> CargoResult<()> {
child.init(false)?;
let url = child
.url()
.ok_or_else(|| internal("non-utf8 url for submodule"))?;
let url = child.url().ok_or_else(|| {
anyhow::format_err!("non-utf8 url for submodule {:?}?", child.path())
})?;

// A submodule which is listed in .gitmodules but not actually
// checked out will not have a head id, so we should ignore it.
Expand Down Expand Up @@ -393,11 +393,11 @@ impl<'a> GitCheckout<'a> {
// Fetch data from origin and reset to the head commit
let refspec = "refs/heads/*:refs/heads/*";
fetch(&mut repo, url, refspec, cargo_config).chain_err(|| {
internal(format!(
format!(
"failed to fetch submodule `{}` from {}",
child.name().unwrap_or(""),
url
))
)
})?;

let obj = repo.find_object(head, None)?;
Expand Down
Loading