]>
Commit | Line | Data |
---|---|---|
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 | 16 | extern crate atty; |
a46df8fe | 17 | extern crate bytesize; |
16bde4e0 | 18 | extern crate clap; |
1e682848 AC |
19 | #[cfg(target_os = "macos")] |
20 | extern crate core_foundation; | |
a4c54384 | 21 | extern crate crates_io as registry; |
8ea90e96 | 22 | extern crate crossbeam_utils; |
18e884d8 | 23 | extern crate curl; |
0b0f089d | 24 | extern crate curl_sys; |
1e682848 AC |
25 | #[macro_use] |
26 | extern crate failure; | |
7d49029a | 27 | extern crate filetime; |
69c16fc6 | 28 | extern crate flate2; |
8eac1d62 | 29 | extern crate fs2; |
641f7ff2 | 30 | #[cfg(windows)] |
31 | extern crate fwdansi; | |
c64fd71e | 32 | extern crate git2; |
2d653915 | 33 | extern crate glob; |
10373f40 | 34 | extern crate hex; |
fdb9f1bd | 35 | extern crate home; |
c072ba42 | 36 | extern crate ignore; |
cbf25a9b | 37 | extern crate jobserver; |
1e682848 AC |
38 | #[macro_use] |
39 | extern crate lazy_static; | |
7f3e86e0 | 40 | extern crate lazycell; |
a6dad622 | 41 | extern crate libc; |
632780eb | 42 | extern crate libgit2_sys; |
1e682848 AC |
43 | #[macro_use] |
44 | extern crate log; | |
80fe0e6d | 45 | extern crate num_cpus; |
48d0708a | 46 | extern crate opener; |
b02ba377 | 47 | extern crate rustfix; |
599db099 | 48 | extern crate same_file; |
c64fd71e | 49 | extern crate semver; |
d6412245 | 50 | #[macro_use] |
a5a298f1 | 51 | extern crate serde; |
1e682848 AC |
52 | #[macro_use] |
53 | extern crate serde_derive; | |
a5a298f1 | 54 | extern crate serde_ignored; |
1e682848 AC |
55 | #[macro_use] |
56 | extern crate serde_json; | |
dad9fe66 | 57 | extern crate im_rc; |
d105e752 | 58 | extern crate shell_escape; |
69c16fc6 | 59 | extern crate tar; |
8daf81e1 | 60 | extern crate tempfile; |
f8fb0a02 | 61 | extern crate termcolor; |
e465ace4 | 62 | extern crate toml; |
a8081a00 | 63 | extern crate unicode_width; |
c64fd71e | 64 | extern crate url; |
5fb7a4f1 | 65 | |
3b93c575 | 66 | use std::fmt; |
def249f9 | 67 | |
37cffbe0 | 68 | use failure::Error; |
dad9fe66 | 69 | use serde::ser; |
68703565 | 70 | |
04ddd4d0 DW |
71 | use crate::core::shell::Verbosity::Verbose; |
72 | use crate::core::Shell; | |
64ff29ff | 73 | |
04ddd4d0 DW |
74 | pub use crate::util::errors::Internal; |
75 | pub use crate::util::{CargoError, CargoResult, CliError, CliResult, Config}; | |
c1b99c18 | 76 | |
676edacf | 77 | pub const CARGO_ENV: &str = "CARGO"; |
015a08a0 | 78 | |
de70d817 AC |
79 | #[macro_use] |
80 | mod macros; | |
81 | ||
4b9fbcb2 | 82 | pub mod core; |
62bff631 | 83 | pub mod ops; |
5d7ece5b CL |
84 | pub mod sources; |
85 | pub mod util; | |
62bff631 | 86 | |
775c900e NF |
87 | pub struct CommitInfo { |
88 | pub short_commit_hash: String, | |
89 | pub commit_hash: String, | |
90 | pub commit_date: String, | |
91 | } | |
92 | ||
93 | pub 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 | ||
100 | pub 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 | ||
110 | impl 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 |
130 | pub 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 | 135 | pub 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 |
174 | pub 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 | 181 | fn 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 | 210 | pub 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 | } |