1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
// For various reasons, some idioms are still allow'ed, but we would like to
// test and enforce them.
#![warn(rust_2018_idioms)]
#![cfg_attr(test, deny(warnings))]
// Due to some of the default clippy lints being somewhat subjective and not
// necessarily an improvement, we prefer to not use them at this time.
#![allow(clippy::all)]
#![allow(rustdoc::private_intra_doc_links)]
//! # Cargo as a library
//!
//! Cargo, the Rust package manager, is also provided as a library.
//!
//! There are two places you can find API documentation of cargo-the-library,
//!
//! - <https://docs.rs/cargo> and
//! - <https://doc.rust-lang.org/nightly/nightly-rustc/cargo>.
//!
//! Each of them targets on a slightly different audience.
//!
//! ## For external tool developers
//!
//! The documentation on <https://docs.rs/cargo> contains public-facing items in cargo-the-library.
//! External tool developers may find it useful when trying to reuse existing building blocks from Cargo.
//! However, using Cargo as a library has drawbacks, especially cargo-the-library is unstable,
//! and there is no clear path to stabilize it soon at the time of writing.
//! See [The Cargo Book: External tools] for more on this topic.
//!
//! Cargo API documentation on docs.rs gets updates along with each Rust release.
//! Its version always has a 0 major version to state it is unstable.
//! The minor version is always +1 of rustc's minor version
//! (that is, `cargo 0.66.0` corresponds to `rustc 1.65`).
//!
//! ## For Cargo contributors
//!
//! The documentation on <https://doc.rust-lang.org/nightly/nightly-rustc/cargo> contains all items in Cargo.
//! Contributors of Cargo may find it useful as a reference of Cargo's implementation details.
//! It's built with `--document-private-items` rustdoc flag,
//! so you might expect to see some noise and strange items here.
//! The Cargo team and contributors strive for jotting down every details
//! from their brains in each issue and PR.
//! However, something might just disappear in the air with no reason.
//! This documentation can be seen as their extended minds,
//! sharing designs and hacks behind both public and private interfaces.
//!
//! If you are just diving into Cargo internals, [Cargo Architecture Overview]
//! is the best material to get a broader context of how Cargo works under the hood.
//! Things also worth a read are important concepts reside in source code,
//! which Cargo developers have been crafting for a while, namely
//!
//! - [`cargo::core::resolver`](crate::core::resolver),
//! - [`cargo::core::compiler::fingerprint`](core/compiler/fingerprint/index.html),
//! - [`cargo::util::config`](crate::util::config),
//! - [`cargo::ops::fix`](ops/fix/index.html), and
//! - [`cargo::sources::registry`](crate::sources::registry).
//!
//! This API documentation is published on each push of rust-lang/cargo master branch.
//! In other words, it always reflects the latest doc comments in source code on master branch.
//!
//! ## Contribute to Cargo documentations
//!
//! The Cargo team always continues improving all external and internal documentations.
//! If you spot anything could be better, don't hesitate to discuss with the team on
//! Zulip [`t-cargo` stream], or [submit an issue] right on GitHub.
//! There is also an issue label [`A-documenting-cargo-itself`],
//! which is generally for documenting user-facing [The Cargo Book],
//! but the Cargo team is welcome any form of enhancement for the [Cargo Contributor Guide]
//! and this API documentation as well.
//!
//! [The Cargo Book: External tools]: https://doc.rust-lang.org/stable/cargo/reference/external-tools.html
//! [Cargo Architecture Overview]: https://doc.crates.io/contrib/architecture
//! [`t-cargo` stream]: https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo
//! [submit an issue]: https://github.com/rust-lang/cargo/issues/new/choose
//! [`A-documenting-cargo-itself`]: https://github.com/rust-lang/cargo/labels/A-documenting-cargo-itself
//! [The Cargo Book]: https://doc.rust-lang.org/cargo/
//! [Cargo Contributor Guide]: https://doc.crates.io/contrib/
use crate::core::shell::Verbosity::Verbose;
use crate::core::Shell;
use anyhow::Error;
use log::debug;
pub use crate::util::errors::{AlreadyPrintedError, InternalError, VerboseError};
pub use crate::util::{indented_lines, CargoResult, CliError, CliResult, Config};
pub use crate::version::version;
pub const CARGO_ENV: &str = "CARGO";
#[macro_use]
mod macros;
pub mod core;
pub mod ops;
pub mod sources;
pub mod util;
mod version;
pub fn exit_with_error(err: CliError, shell: &mut Shell) -> ! {
debug!("exit_with_error; err={:?}", err);
if let Some(ref err) = err.error {
if let Some(clap_err) = err.downcast_ref::<clap::Error>() {
let exit_code = if clap_err.use_stderr() { 1 } else { 0 };
let _ = clap_err.print();
std::process::exit(exit_code)
}
}
let CliError { error, exit_code } = err;
if let Some(error) = error {
display_error(&error, shell);
}
std::process::exit(exit_code)
}
/// Displays an error, and all its causes, to stderr.
pub fn display_error(err: &Error, shell: &mut Shell) {
debug!("display_error; err={:?}", err);
_display_error(err, shell, true);
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!("cargo {}", version())));
// Once backtraces are stabilized, this should print out a backtrace
// if it is available.
}
}
/// Displays a warning, with an error object providing detailed information
/// and context.
pub fn display_warning_with_error(warning: &str, err: &Error, shell: &mut Shell) {
drop(shell.warn(warning));
drop(writeln!(shell.err()));
_display_error(err, shell, false);
}
fn _display_error(err: &Error, shell: &mut Shell, as_err: bool) -> bool {
for (i, err) in err.chain().enumerate() {
// If we're not in verbose mode then only print cause chain until one
// marked as `VerboseError` appears.
//
// Generally the top error shouldn't be verbose, but check it anyways.
if shell.verbosity() != Verbose && err.is::<VerboseError>() {
return true;
}
if err.is::<AlreadyPrintedError>() {
break;
}
if i == 0 {
if as_err {
drop(shell.error(&err));
} else {
drop(writeln!(shell.err(), "{}", err));
}
} else {
drop(writeln!(shell.err(), "\nCaused by:"));
drop(write!(shell.err(), "{}", indented_lines(&err.to_string())));
}
}
false
}