]> git.proxmox.com Git - cargo.git/blame - src/cargo/lib.rs
Upgrade to Rust 2018
[cargo.git] / src / cargo / lib.rs
CommitLineData
7b059db1 1#![cfg_attr(test, deny(warnings))]
08077302 2// Clippy isn't enforced by CI, and know that @alexcrichton isn't a fan :)
dad9fe66
E
3#![cfg_attr(feature = "cargo-clippy", allow(clippy::boxed_local))] // bug rust-lang-nursery/rust-clippy#1123
4#![cfg_attr(feature = "cargo-clippy", allow(clippy::cyclomatic_complexity))] // large project
5#![cfg_attr(feature = "cargo-clippy", allow(clippy::derive_hash_xor_eq))] // there's an intentional incoherence
6#![cfg_attr(feature = "cargo-clippy", allow(clippy::explicit_into_iter_loop))] // explicit loops are clearer
7#![cfg_attr(feature = "cargo-clippy", allow(clippy::explicit_iter_loop))] // explicit loops are clearer
8#![cfg_attr(feature = "cargo-clippy", allow(clippy::identity_op))] // used for vertical alignment
9#![cfg_attr(feature = "cargo-clippy", allow(clippy::implicit_hasher))] // large project
10#![cfg_attr(feature = "cargo-clippy", allow(clippy::large_enum_variant))] // large project
11#![cfg_attr(feature = "cargo-clippy", allow(clippy::redundant_closure_call))] // closures over try catch blocks
12#![cfg_attr(feature = "cargo-clippy", allow(clippy::too_many_arguments))] // large project
13#![cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))] // there's an exceptionally complex type
14#![cfg_attr(feature = "cargo-clippy", allow(clippy::wrong_self_convention))] // perhaps Rc should be special cased in Clippy?
676edacf 15
9629f99d 16extern crate atty;
a46df8fe 17extern crate bytesize;
16bde4e0 18extern crate clap;
1e682848
AC
19#[cfg(target_os = "macos")]
20extern crate core_foundation;
a4c54384 21extern crate crates_io as registry;
8ea90e96 22extern crate crossbeam_utils;
18e884d8 23extern crate curl;
0b0f089d 24extern crate curl_sys;
1e682848
AC
25#[macro_use]
26extern crate failure;
7d49029a 27extern crate filetime;
69c16fc6 28extern crate flate2;
8eac1d62 29extern crate fs2;
641f7ff2 30#[cfg(windows)]
31extern crate fwdansi;
c64fd71e 32extern crate git2;
2d653915 33extern crate glob;
10373f40 34extern crate hex;
fdb9f1bd 35extern crate home;
c072ba42 36extern crate ignore;
cbf25a9b 37extern crate jobserver;
1e682848
AC
38#[macro_use]
39extern crate lazy_static;
7f3e86e0 40extern crate lazycell;
a6dad622 41extern crate libc;
632780eb 42extern crate libgit2_sys;
1e682848
AC
43#[macro_use]
44extern crate log;
80fe0e6d 45extern crate num_cpus;
48d0708a 46extern crate opener;
b02ba377 47extern crate rustfix;
599db099 48extern crate same_file;
c64fd71e 49extern crate semver;
d6412245 50#[macro_use]
a5a298f1 51extern crate serde;
1e682848
AC
52#[macro_use]
53extern crate serde_derive;
a5a298f1 54extern crate serde_ignored;
1e682848
AC
55#[macro_use]
56extern crate serde_json;
dad9fe66 57extern crate im_rc;
d105e752 58extern crate shell_escape;
69c16fc6 59extern crate tar;
8daf81e1 60extern crate tempfile;
f8fb0a02 61extern crate termcolor;
e465ace4 62extern crate toml;
a8081a00 63extern crate unicode_width;
c64fd71e 64extern crate url;
5fb7a4f1 65
3b93c575 66use std::fmt;
def249f9 67
37cffbe0 68use failure::Error;
dad9fe66 69use serde::ser;
68703565 70
04ddd4d0
DW
71use crate::core::shell::Verbosity::Verbose;
72use crate::core::Shell;
64ff29ff 73
04ddd4d0
DW
74pub use crate::util::errors::Internal;
75pub use crate::util::{CargoError, CargoResult, CliError, CliResult, Config};
c1b99c18 76
676edacf 77pub const CARGO_ENV: &str = "CARGO";
015a08a0 78
de70d817
AC
79#[macro_use]
80mod macros;
81
4b9fbcb2 82pub mod core;
62bff631 83pub mod ops;
5d7ece5b
CL
84pub mod sources;
85pub mod util;
62bff631 86
775c900e
NF
87pub struct CommitInfo {
88 pub short_commit_hash: String,
89 pub commit_hash: String,
90 pub commit_date: String,
91}
92
93pub struct CfgInfo {
94 // Information about the git repository we may have been built from.
95 pub commit_info: Option<CommitInfo>,
775c900e
NF
96 // The release channel we were built for.
97 pub release_channel: String,
98}
99
100pub struct VersionInfo {
cc971ee5
AK
101 pub major: u8,
102 pub minor: u8,
103 pub patch: u8,
775c900e
NF
104 pub pre_release: Option<String>,
105 // Information that's only available when we were built with
106 // configure/make, rather than cargo itself.
107 pub cfg_info: Option<CfgInfo>,
108}
109
110impl fmt::Display for VersionInfo {
111 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1e682848 112 write!(f, "cargo {}.{}.{}", self.major, self.minor, self.patch)?;
c5611a32
AB
113 if let Some(channel) = self.cfg_info.as_ref().map(|ci| &ci.release_channel) {
114 if channel != "stable" {
115 write!(f, "-{}", channel)?;
8798bf0d 116 let empty = String::new();
c5611a32
AB
117 write!(f, "{}", self.pre_release.as_ref().unwrap_or(&empty))?;
118 }
775c900e
NF
119 };
120
121 if let Some(ref cfg) = self.cfg_info {
7e6c83fa 122 if let Some(ref ci) = cfg.commit_info {
1e682848 123 write!(f, " ({} {})", ci.short_commit_hash, ci.commit_date)?;
775c900e
NF
124 }
125 };
126 Ok(())
127 }
128}
129
a5a298f1
AC
130pub fn print_json<T: ser::Serialize>(obj: &T) {
131 let encoded = serde_json::to_string(&obj).unwrap();
0c7e73c2
AK
132 println!("{}", encoded);
133}
134
f8fb0a02 135pub fn exit_with_error(err: CliError, shell: &mut Shell) -> ! {
ef043577 136 debug!("exit_with_error; err={:?}", err);
16bde4e0
AK
137 if let Some(ref err) = err.error {
138 if let Some(clap_err) = err.downcast_ref::<clap::Error>() {
139 clap_err.exit()
140 }
141 }
19bea0ad 142
1e682848
AC
143 let CliError {
144 error,
145 exit_code,
146 unknown,
147 } = err;
61cb937e
AK
148 // exit_code == 0 is non-fatal error, e.g. docopt version info
149 let fatal = exit_code != 0;
68703565 150
f8fb0a02 151 let hide = unknown && shell.verbosity() != Verbose;
61cb937e 152
860f38a1 153 if let Some(error) = error {
f8fb0a02
AC
154 if hide {
155 drop(shell.error("An unknown error occurred"))
860f38a1 156 } else if fatal {
f8fb0a02 157 drop(shell.error(&error))
860f38a1 158 } else {
836e3efd 159 println!("{}", error);
f8fb0a02 160 }
860f38a1 161
37cffbe0 162 if !handle_cause(&error, shell) || hide {
1e682848
AC
163 drop(writeln!(
164 shell.err(),
165 "\nTo learn more, run the command again \
166 with --verbose."
167 ));
860f38a1 168 }
c9206131 169 }
21322f07 170
3b93c575 171 std::process::exit(exit_code)
3a15f5b7
YK
172}
173
385b54b3
E
174pub fn handle_error(err: &CargoError, shell: &mut Shell) {
175 debug!("handle_error; err={:?}", err);
4c54520d 176
385b54b3
E
177 let _ignored_result = shell.error(err);
178 handle_cause(err, shell);
4c54520d 179}
180
37cffbe0 181fn handle_cause(cargo_err: &Error, shell: &mut Shell) -> bool {
385b54b3 182 fn print(error: &str, shell: &mut Shell) {
f8fb0a02
AC
183 drop(writeln!(shell.err(), "\nCaused by:"));
184 drop(writeln!(shell.err(), " {}", error));
4df6da4a 185 }
e95044e3 186
f8fb0a02 187 let verbose = shell.verbosity();
e95044e3 188
189 if verbose == Verbose {
37cffbe0
AC
190 // The first error has already been printed to the shell
191 // Print all remaining errors
adbd625e 192 for err in cargo_err.iter_causes() {
385b54b3 193 print(&err.to_string(), shell);
e95044e3 194 }
c7de4859 195 } else {
37cffbe0
AC
196 // The first error has already been printed to the shell
197 // Print remaining errors until one marked as Internal appears
adbd625e 198 for err in cargo_err.iter_causes() {
37cffbe0 199 if err.downcast_ref::<Internal>().is_some() {
e95044e3 200 return false;
201 }
202
385b54b3 203 print(&err.to_string(), shell);
e95044e3 204 }
205 }
206
207 true
fce99832
YK
208}
209
775c900e 210pub fn version() -> VersionInfo {
775c900e 211 macro_rules! option_env_str {
dad9fe66
E
212 ($name:expr) => {
213 option_env!($name).map(|s| s.to_string())
214 };
775c900e 215 }
cc971ee5
AK
216
217 // So this is pretty horrible...
218 // There are two versions at play here:
219 // - version of cargo-the-binary, which you see when you type `cargo --version`
220 // - version of cargo-the-library, which you download from crates.io for use
3492a390 221 // in your packages.
cc971ee5
AK
222 //
223 // We want to make the `binary` version the same as the corresponding Rust/rustc release.
224 // At the same time, we want to keep the library version at `0.x`, because Cargo as
225 // a library is (and probably will always be) unstable.
226 //
227 // Historically, Cargo used the same version number for both the binary and the library.
228 // Specifically, rustc 1.x.z was paired with cargo 0.x+1.w.
229 // We continue to use this scheme for the library, but transform it to 1.x.w for the purposes
230 // of `cargo --version`.
231 let major = 1;
232 let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap() - 1;
233 let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u8>().unwrap();
234
775c900e
NF
235 match option_env!("CFG_RELEASE_CHANNEL") {
236 // We have environment variables set up from configure/make.
237 Some(_) => {
1e682848
AC
238 let commit_info = option_env!("CFG_COMMIT_HASH").map(|s| CommitInfo {
239 commit_hash: s.to_string(),
240 short_commit_hash: option_env_str!("CFG_SHORT_COMMIT_HASH").unwrap(),
241 commit_date: option_env_str!("CFG_COMMIT_DATE").unwrap(),
242 });
775c900e 243 VersionInfo {
cc971ee5
AK
244 major,
245 minor,
246 patch,
f6fd0fd9 247 pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
775c900e 248 cfg_info: Some(CfgInfo {
775c900e 249 release_channel: option_env_str!("CFG_RELEASE_CHANNEL").unwrap(),
0247dc42 250 commit_info,
775c900e
NF
251 }),
252 }
775c900e 253 }
1e682848
AC
254 // We are being compiled by Cargo itself.
255 None => VersionInfo {
256 major,
257 minor,
258 patch,
259 pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
260 cfg_info: None,
261 },
775c900e 262 }
fce99832 263}