]> git.proxmox.com Git - cargo.git/blame - src/cargo/lib.rs
Auto merge of #9467 - ehuss:install-metadata, r=alexcrichton
[cargo.git] / src / cargo / lib.rs
CommitLineData
00f3fc90
EH
1// For various reasons, some idioms are still allow'ed, but we would like to
2// test and enforce them.
ec21e12d 3#![warn(rust_2018_idioms)]
00f3fc90 4#![cfg_attr(test, deny(warnings))]
10eb56f2
EH
5// Due to some of the default clippy lints being somewhat subjective and not
6// necessarily an improvement, we prefer to not use them at this time.
7#![allow(clippy::all)]
ef0b4776 8#![warn(clippy::needless_borrow)]
10eb56f2 9#![warn(clippy::redundant_clone)]
676edacf 10
04ddd4d0
DW
11use crate::core::shell::Verbosity::Verbose;
12use crate::core::Shell;
3a18c89a
AC
13use anyhow::Error;
14use log::debug;
3a18c89a 15use std::fmt;
64ff29ff 16
0d44a826 17pub use crate::util::errors::{InternalError, VerboseError};
00615fc5 18pub use crate::util::{indented_lines, CargoResult, CliError, CliResult, Config};
c1b99c18 19
676edacf 20pub const CARGO_ENV: &str = "CARGO";
015a08a0 21
de70d817
AC
22#[macro_use]
23mod macros;
24
4b9fbcb2 25pub mod core;
62bff631 26pub mod ops;
5d7ece5b
CL
27pub mod sources;
28pub mod util;
62bff631 29
775c900e
NF
30pub struct CommitInfo {
31 pub short_commit_hash: String,
32 pub commit_hash: String,
33 pub commit_date: String,
34}
35
36pub struct CfgInfo {
f7c91ba6 37 // Information about the Git repository we may have been built from.
775c900e 38 pub commit_info: Option<CommitInfo>,
775c900e
NF
39 // The release channel we were built for.
40 pub release_channel: String,
41}
42
43pub struct VersionInfo {
cc971ee5
AK
44 pub major: u8,
45 pub minor: u8,
46 pub patch: u8,
775c900e
NF
47 pub pre_release: Option<String>,
48 // Information that's only available when we were built with
f7c91ba6 49 // configure/make, rather than Cargo itself.
775c900e
NF
50 pub cfg_info: Option<CfgInfo>,
51}
52
53impl fmt::Display for VersionInfo {
b8b7faee 54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1e682848 55 write!(f, "cargo {}.{}.{}", self.major, self.minor, self.patch)?;
c5611a32
AB
56 if let Some(channel) = self.cfg_info.as_ref().map(|ci| &ci.release_channel) {
57 if channel != "stable" {
58 write!(f, "-{}", channel)?;
8798bf0d 59 let empty = String::new();
c5611a32
AB
60 write!(f, "{}", self.pre_release.as_ref().unwrap_or(&empty))?;
61 }
775c900e
NF
62 };
63
64 if let Some(ref cfg) = self.cfg_info {
7e6c83fa 65 if let Some(ref ci) = cfg.commit_info {
1e682848 66 write!(f, " ({} {})", ci.short_commit_hash, ci.commit_date)?;
775c900e
NF
67 }
68 };
69 Ok(())
70 }
71}
72
f8fb0a02 73pub fn exit_with_error(err: CliError, shell: &mut Shell) -> ! {
ef043577 74 debug!("exit_with_error; err={:?}", err);
16bde4e0
AK
75 if let Some(ref err) = err.error {
76 if let Some(clap_err) = err.downcast_ref::<clap::Error>() {
77 clap_err.exit()
78 }
79 }
19bea0ad 80
0d44a826 81 let CliError { error, exit_code } = err;
860f38a1 82 if let Some(error) = error {
0d44a826 83 display_error(&error, shell);
c9206131 84 }
21322f07 85
3b93c575 86 std::process::exit(exit_code)
3a15f5b7
YK
87}
88
0d44a826
EH
89/// Displays an error, and all its causes, to stderr.
90pub fn display_error(err: &Error, shell: &mut Shell) {
91 debug!("display_error; err={:?}", err);
b64d0f36 92 let has_verbose = _display_error(err, shell, true);
0d44a826
EH
93 if has_verbose {
94 drop(writeln!(
95 shell.err(),
96 "\nTo learn more, run the command again with --verbose."
97 ));
98 }
99 if err
100 .chain()
101 .any(|e| e.downcast_ref::<InternalError>().is_some())
102 {
103 drop(shell.note("this is an unexpected cargo internal error"));
104 drop(
105 shell.note(
106 "we would appreciate a bug report: https://github.com/rust-lang/cargo/issues/",
107 ),
108 );
109 drop(shell.note(format!("{}", version())));
110 // Once backtraces are stabilized, this should print out a backtrace
111 // if it is available.
112 }
4c54520d 113}
114
b64d0f36
EH
115/// Displays a warning, with an error object providing detailed information
116/// and context.
117pub fn display_warning_with_error(warning: &str, err: &Error, shell: &mut Shell) {
118 drop(shell.warn(warning));
6694fdb6 119 drop(writeln!(shell.err()));
b64d0f36
EH
120 _display_error(err, shell, false);
121}
122
123fn _display_error(err: &Error, shell: &mut Shell, as_err: bool) -> bool {
0d44a826
EH
124 let verbosity = shell.verbosity();
125 let is_verbose = |e: &(dyn std::error::Error + 'static)| -> bool {
126 verbosity != Verbose && e.downcast_ref::<VerboseError>().is_some()
127 };
128 // Generally the top error shouldn't be verbose, but check it anyways.
129 if is_verbose(err.as_ref()) {
130 return true;
4df6da4a 131 }
b64d0f36
EH
132 if as_err {
133 drop(shell.error(&err));
134 } else {
135 drop(writeln!(shell.err(), "{}", err));
136 }
0d44a826 137 for cause in err.chain().skip(1) {
3842d8e6 138 // If we're not in verbose mode then print remaining errors until one
0d44a826
EH
139 // marked as `VerboseError` appears.
140 if is_verbose(cause) {
141 return true;
e95044e3 142 }
0d44a826 143 drop(writeln!(shell.err(), "\nCaused by:"));
00615fc5
EH
144 drop(write!(
145 shell.err(),
146 "{}",
147 indented_lines(&cause.to_string())
148 ));
e95044e3 149 }
0d44a826 150 false
fce99832
YK
151}
152
775c900e 153pub fn version() -> VersionInfo {
775c900e 154 macro_rules! option_env_str {
dad9fe66
E
155 ($name:expr) => {
156 option_env!($name).map(|s| s.to_string())
157 };
775c900e 158 }
cc971ee5
AK
159
160 // So this is pretty horrible...
161 // There are two versions at play here:
162 // - version of cargo-the-binary, which you see when you type `cargo --version`
163 // - version of cargo-the-library, which you download from crates.io for use
3492a390 164 // in your packages.
cc971ee5
AK
165 //
166 // We want to make the `binary` version the same as the corresponding Rust/rustc release.
167 // At the same time, we want to keep the library version at `0.x`, because Cargo as
168 // a library is (and probably will always be) unstable.
169 //
170 // Historically, Cargo used the same version number for both the binary and the library.
171 // Specifically, rustc 1.x.z was paired with cargo 0.x+1.w.
172 // We continue to use this scheme for the library, but transform it to 1.x.w for the purposes
173 // of `cargo --version`.
174 let major = 1;
175 let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap() - 1;
176 let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u8>().unwrap();
177
775c900e
NF
178 match option_env!("CFG_RELEASE_CHANNEL") {
179 // We have environment variables set up from configure/make.
180 Some(_) => {
1e682848
AC
181 let commit_info = option_env!("CFG_COMMIT_HASH").map(|s| CommitInfo {
182 commit_hash: s.to_string(),
183 short_commit_hash: option_env_str!("CFG_SHORT_COMMIT_HASH").unwrap(),
184 commit_date: option_env_str!("CFG_COMMIT_DATE").unwrap(),
185 });
775c900e 186 VersionInfo {
cc971ee5
AK
187 major,
188 minor,
189 patch,
f6fd0fd9 190 pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
775c900e 191 cfg_info: Some(CfgInfo {
775c900e 192 release_channel: option_env_str!("CFG_RELEASE_CHANNEL").unwrap(),
0247dc42 193 commit_info,
775c900e
NF
194 }),
195 }
775c900e 196 }
1e682848
AC
197 // We are being compiled by Cargo itself.
198 None => VersionInfo {
199 major,
200 minor,
201 patch,
202 pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
203 cfg_info: None,
204 },
775c900e 205 }
fce99832 206}