]> git.proxmox.com Git - cargo.git/blame - src/bin/cargo/main.rs
Auto merge of #9212 - vidbina:fix-spelling-worksapce-to-workspace, r=ehuss
[cargo.git] / src / bin / cargo / main.rs
CommitLineData
92bf2c36 1#![warn(rust_2018_idioms)] // while we're getting used to 2018
9ed82b57 2#![allow(clippy::redundant_closure)] // there's a false positive
ef0b4776 3#![warn(clippy::needless_borrow)]
a91a12b4 4#![warn(clippy::redundant_clone)]
1ca6830e 5
0f157f52 6use std::collections::{BTreeMap, BTreeSet};
ee5e24ff 7use std::env;
a6dad622 8use std::fs;
ef4c09f9 9use std::path::{Path, PathBuf};
ba273af5 10
901065f5 11use cargo::core::shell::Shell;
7d7fe679 12use cargo::util::{self, closest_msg, command_prelude, CargoResult, CliResult, Config};
37cffbe0 13use cargo::util::{CliError, ProcessError};
3a15f5b7 14
38f81e05 15mod cli;
66bb9dc3 16mod commands;
7acd343b 17
04ddd4d0 18use crate::command_prelude::*;
c3422cfc 19
3512d997 20fn main() {
aa8eff88 21 #[cfg(feature = "pretty-env-logger")]
782266aa 22 pretty_env_logger::init_custom_env("CARGO_LOG");
aa8eff88 23 #[cfg(not(feature = "pretty-env-logger"))]
782266aa 24 env_logger::init_from_env("CARGO_LOG");
75bb1906 25 cargo::core::maybe_allow_nightly_features();
3b93c575 26
89c09e20 27 let mut config = match Config::default() {
3b93c575
AK
28 Ok(cfg) => cfg,
29 Err(e) => {
f8fb0a02 30 let mut shell = Shell::new();
ef043577 31 cargo::exit_with_error(e.into(), &mut shell)
3b93c575
AK
32 }
33 };
34
b02ba377
AC
35 let result = match cargo::ops::fix_maybe_exec_rustc() {
36 Ok(true) => Ok(()),
37 Ok(false) => {
b02ba377
AC
38 let _token = cargo::util::job::setup();
39 cli::main(&mut config)
40 }
41 Err(e) => Err(CliError::from(e)),
16bde4e0
AK
42 };
43
44 match result {
ef043577 45 Err(e) => cargo::exit_with_error(e, &mut *config.shell()),
ef4c09f9 46 Ok(()) => {}
3b93c575 47 }
3512d997 48}
3a15f5b7 49
2ae8df65
C
50/// Table for defining the aliases which come builtin in `Cargo`.
51/// The contents are structured as: `(alias, aliased_command, description)`.
52const BUILTIN_ALIASES: [(&str, &str, &str); 4] = [
53 ("b", "build", "alias: build"),
54 ("c", "check", "alias: check"),
55 ("r", "run", "alias: run"),
56 ("t", "test", "alias: test"),
26beca06
C
57];
58
59/// Function which contains the list of all of the builtin aliases and it's
60/// corresponding execs represented as &str.
2ae8df65
C
61fn builtin_aliases_execs(cmd: &str) -> Option<&(&str, &str, &str)> {
62 BUILTIN_ALIASES.iter().find(|alias| alias.0 == cmd)
26beca06
C
63}
64
23591fe5 65fn aliased_command(config: &Config, command: &str) -> CargoResult<Option<Vec<String>>> {
66739f1c 66 let alias_name = format!("alias.{}", command);
e8f37dae
EH
67 let user_alias = match config.get_string(&alias_name) {
68 Ok(Some(record)) => Some(
69 record
70 .val
71 .split_whitespace()
72 .map(|s| s.to_string())
73 .collect(),
74 ),
75 Ok(None) => None,
5bba4261 76 Err(_) => config.get::<Option<Vec<String>>>(&alias_name)?,
e8f37dae 77 };
26beca06
C
78
79 let result = user_alias.or_else(|| match builtin_aliases_execs(command) {
2ae8df65 80 Some(command_str) => Some(vec![command_str.1.to_string()]),
26beca06 81 None => None,
e8f37dae
EH
82 });
83 Ok(result)
66739f1c
SBI
84}
85
e68c682a 86/// List all runnable commands
c3422cfc 87fn list_commands(config: &Config) -> BTreeSet<CommandInfo> {
e68c682a
AK
88 let prefix = "cargo-";
89 let suffix = env::consts::EXE_SUFFIX;
90 let mut commands = BTreeSet::new();
91 for dir in search_directories(config) {
92 let entries = match fs::read_dir(dir) {
93 Ok(entries) => entries,
94 _ => continue,
95 };
96 for entry in entries.filter_map(|e| e.ok()) {
97 let path = entry.path();
98 let filename = match path.file_name().and_then(|s| s.to_str()) {
99 Some(filename) => filename,
100 _ => continue,
101 };
102 if !filename.starts_with(prefix) || !filename.ends_with(suffix) {
103 continue;
104 }
105 if is_executable(entry.path()) {
106 let end = filename.len() - suffix.len();
c3422cfc
DW
107 commands.insert(CommandInfo::External {
108 name: filename[prefix.len()..end].to_string(),
109 path: path.clone(),
110 });
e68c682a
AK
111 }
112 }
113 }
114
115 for cmd in commands::builtin() {
c3422cfc
DW
116 commands.insert(CommandInfo::BuiltIn {
117 name: cmd.get_name().to_string(),
af2c3555 118 about: cmd.p.meta.about.map(|s| s.to_string()),
c3422cfc 119 });
e68c682a 120 }
2ae8df65
C
121
122 // Add the builtin_aliases and them descriptions to the
123 // `commands` `BTreeSet`.
26beca06
C
124 for command in &BUILTIN_ALIASES {
125 commands.insert(CommandInfo::BuiltIn {
126 name: command.0.to_string(),
2ae8df65 127 about: Some(command.2.to_string()),
26beca06
C
128 });
129 }
e68c682a
AK
130
131 commands
132}
133
ff3e880c
ZL
134/// List all runnable aliases
135fn list_aliases(config: &Config) -> Vec<String> {
0f157f52
ZL
136 match config.get::<BTreeMap<String, String>>("alias") {
137 Ok(aliases) => aliases.keys().map(|a| a.to_string()).collect(),
ff3e880c
ZL
138 Err(_) => Vec::new(),
139 }
140}
141
81ce3e1b 142fn execute_external_subcommand(config: &Config, cmd: &str, args: &[&str]) -> CliResult {
20b768e6
AC
143 let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
144 let path = search_directories(config)
ef4c09f9 145 .iter()
146 .map(|dir| dir.join(&command_exe))
147 .find(|file| is_executable(file));
20b768e6 148 let command = match path {
7ed31fab 149 Some(command) => command,
12f5de8e 150 None => {
ff3e880c
ZL
151 let commands: Vec<String> = list_commands(config)
152 .iter()
153 .map(|c| c.name().to_string())
154 .collect();
155 let aliases = list_aliases(config);
156 let suggestions = commands.iter().chain(aliases.iter());
157 let did_you_mean = closest_msg(cmd, suggestions, |c| c);
3a18c89a 158 let err = anyhow::format_err!("no such subcommand: `{}`{}", cmd, did_you_mean);
1e682848 159 return Err(CliError::new(err, 101));
12f5de8e 160 }
8cce8996 161 };
015a08a0
VK
162
163 let cargo_exe = config.cargo_exe()?;
164 let err = match util::process(&command)
165 .env(cargo::CARGO_ENV, cargo_exe)
deb1c1e1 166 .args(args)
1e682848
AC
167 .exec_replace()
168 {
fdc5b07c
AC
169 Ok(()) => return Ok(()),
170 Err(e) => e,
171 };
172
37cffbe0 173 if let Some(perr) = err.downcast_ref::<ProcessError>() {
cc5e9df6 174 if let Some(code) = perr.code {
e95044e3 175 return Err(CliError::code(code));
176 }
fdc5b07c 177 }
48446574 178 Err(CliError::new(err, 101))
a3f6a404 179}
180
a6dad622 181#[cfg(unix)]
7ed31fab 182fn is_executable<P: AsRef<Path>>(path: P) -> bool {
a6dad622 183 use std::os::unix::prelude::*;
ef4c09f9 184 fs::metadata(path)
185 .map(|metadata| metadata.is_file() && metadata.permissions().mode() & 0o111 != 0)
186 .unwrap_or(false)
a6dad622
AC
187}
188#[cfg(windows)]
7ed31fab 189fn is_executable<P: AsRef<Path>>(path: P) -> bool {
4367ec4d 190 path.as_ref().is_file()
a3f6a404 191}
192
20b768e6 193fn search_directories(config: &Config) -> Vec<PathBuf> {
8eac1d62 194 let mut dirs = vec![config.home().clone().into_path_unlocked().join("bin")];
1384050e 195 if let Some(val) = env::var_os("PATH") {
ee5e24ff
AC
196 dirs.extend(env::split_paths(&val));
197 }
a1b3d153 198 dirs
3a15f5b7 199}
b20b0f6b
AC
200
201fn init_git_transports(config: &Config) {
9f932e11
JG
202 // Only use a custom transport if any HTTP options are specified,
203 // such as proxies or custom certificate authorities. The custom
204 // transport, however, is not as well battle-tested.
205
206 match cargo::ops::needs_custom_http_transport(config) {
8eb28ad6 207 Ok(true) => {}
ef4c09f9 208 _ => return,
b20b0f6b
AC
209 }
210
211 let handle = match cargo::ops::http_handle(config) {
212 Ok(handle) => handle,
213 Err(..) => return,
214 };
215
216 // The unsafety of the registration function derives from two aspects:
217 //
218 // 1. This call must be synchronized with all other registration calls as
219 // well as construction of new transports.
220 // 2. The argument is leaked.
221 //
222 // We're clear on point (1) because this is only called at the start of this
223 // binary (we know what the state of the world looks like) and we're mostly
224 // clear on point (2) because we'd only free it after everything is done
225 // anyway
226 unsafe {
227 git2_curl::register(handle);
228 }
229}