mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-25 11:14:46 +00:00
Close the front door for clippy but open the back
This commit is contained in:
parent
2bdc87972c
commit
b0351e4d87
@ -1679,6 +1679,7 @@ thread_local!(
|
||||
pub static RUSTC: Rustc = Rustc::new(
|
||||
PathBuf::from("rustc"),
|
||||
None,
|
||||
None,
|
||||
Path::new("should be path to rustup rustc, but we don't care in tests"),
|
||||
None,
|
||||
).unwrap()
|
||||
|
@ -264,3 +264,22 @@ pub fn sysroot() -> String {
|
||||
let sysroot = String::from_utf8(output.stdout).unwrap();
|
||||
sysroot.trim().to_string()
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn echo_wrapper() -> std::io::Result<std::path::PathBuf> {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let wrapper_path = root().join("rustc-echo-wrapper");
|
||||
std::fs::write(
|
||||
&wrapper_path,
|
||||
r#"#! /bin/bash
|
||||
|
||||
echo "WRAPPER CALLED: $*"
|
||||
"$@""#,
|
||||
)?;
|
||||
|
||||
let mut perms = std::fs::metadata(&wrapper_path)?.permissions();
|
||||
perms.set_mode(0o755);
|
||||
std::fs::set_permissions(&wrapper_path, perms)?;
|
||||
|
||||
Ok(wrapper_path)
|
||||
}
|
||||
|
@ -1,85 +0,0 @@
|
||||
use crate::command_prelude::*;
|
||||
|
||||
use cargo::ops;
|
||||
use cargo::util;
|
||||
|
||||
pub fn cli() -> App {
|
||||
subcommand("clippy-preview")
|
||||
.about("Checks a package to catch common mistakes and improve your Rust code.")
|
||||
.arg(Arg::with_name("args").multiple(true))
|
||||
.arg_package_spec(
|
||||
"Package(s) to check",
|
||||
"Check all packages in the workspace",
|
||||
"Exclude packages from the check",
|
||||
)
|
||||
.arg_jobs()
|
||||
.arg_targets_all(
|
||||
"Check only this package's library",
|
||||
"Check only the specified binary",
|
||||
"Check all binaries",
|
||||
"Check only the specified example",
|
||||
"Check all examples",
|
||||
"Check only the specified test target",
|
||||
"Check all tests",
|
||||
"Check only the specified bench target",
|
||||
"Check all benches",
|
||||
"Check all targets",
|
||||
)
|
||||
.arg_release("Check artifacts in release mode, with optimizations")
|
||||
.arg_profile("Check artifacts with the specified profile")
|
||||
.arg_features()
|
||||
.arg_target_triple("Check for the target triple")
|
||||
.arg_target_dir()
|
||||
.arg_manifest_path()
|
||||
.arg_message_format()
|
||||
.after_help(
|
||||
"\
|
||||
If the `--package` argument is given, then SPEC is a package ID specification
|
||||
which indicates which package should be built. If it is not given, then the
|
||||
current package is built. For more information on SPEC and its format, see the
|
||||
`cargo help pkgid` command.
|
||||
|
||||
All packages in the workspace are checked if the `--workspace` flag is supplied. The
|
||||
`--workspace` flag is automatically assumed for a virtual manifest.
|
||||
Note that `--exclude` has to be specified in conjunction with the `--workspace` flag.
|
||||
|
||||
To allow or deny a lint from the command line you can use `cargo clippy --`
|
||||
with:
|
||||
|
||||
-W --warn OPT Set lint warnings
|
||||
-A --allow OPT Set lint allowed
|
||||
-D --deny OPT Set lint denied
|
||||
-F --forbid OPT Set lint forbidden
|
||||
|
||||
You can use tool lints to allow or deny lints from your code, eg.:
|
||||
|
||||
#[allow(clippy::needless_lifetimes)]
|
||||
",
|
||||
)
|
||||
}
|
||||
|
||||
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
|
||||
let ws = args.workspace(config)?;
|
||||
|
||||
let mode = CompileMode::Check { test: false };
|
||||
let mut compile_opts =
|
||||
args.compile_options(config, mode, Some(&ws), ProfileChecking::Checked)?;
|
||||
|
||||
if !config.cli_unstable().unstable_options {
|
||||
return Err(anyhow::format_err!(
|
||||
"`clippy-preview` is unstable, pass `-Z unstable-options` to enable it"
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
let mut wrapper = util::process(util::config::clippy_driver());
|
||||
|
||||
if let Some(clippy_args) = args.values_of("args") {
|
||||
wrapper.args(&clippy_args.collect::<Vec<_>>());
|
||||
}
|
||||
|
||||
compile_opts.build_config.primary_unit_rustc = Some(wrapper);
|
||||
|
||||
ops::compile(&ws, &compile_opts)?;
|
||||
Ok(())
|
||||
}
|
@ -72,15 +72,6 @@ pub fn cli() -> App {
|
||||
.long("allow-staged")
|
||||
.help("Fix code even if the working directory has staged changes"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("clippy")
|
||||
.long("clippy")
|
||||
.help("Get fix suggestions from clippy instead of rustc")
|
||||
.hidden(true)
|
||||
.multiple(true)
|
||||
.min_values(0)
|
||||
.number_of_values(1),
|
||||
)
|
||||
.after_help(
|
||||
"\
|
||||
This Cargo subcommand will automatically take rustc's suggestions from
|
||||
@ -134,21 +125,6 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
|
||||
// code as we can.
|
||||
let mut opts = args.compile_options(config, mode, Some(&ws), ProfileChecking::Unchecked)?;
|
||||
|
||||
let use_clippy = args.is_present("clippy");
|
||||
|
||||
let clippy_args = args
|
||||
.value_of("clippy")
|
||||
.map(|s| s.split(' ').map(|s| s.to_string()).collect())
|
||||
.or_else(|| Some(vec![]))
|
||||
.filter(|_| use_clippy);
|
||||
|
||||
if use_clippy && !config.cli_unstable().unstable_options {
|
||||
return Err(anyhow::format_err!(
|
||||
"`cargo fix --clippy` is unstable, pass `-Z unstable-options` to enable it"
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
if let CompileFilter::Default { .. } = opts.filter {
|
||||
opts.filter = CompileFilter::Only {
|
||||
all_targets: true,
|
||||
@ -171,7 +147,6 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
|
||||
allow_no_vcs: args.is_present("allow-no-vcs"),
|
||||
allow_staged: args.is_present("allow-staged"),
|
||||
broken_code: args.is_present("broken-code"),
|
||||
clippy_args,
|
||||
},
|
||||
)?;
|
||||
Ok(())
|
||||
|
@ -6,7 +6,6 @@ pub fn builtin() -> Vec<App> {
|
||||
build::cli(),
|
||||
check::cli(),
|
||||
clean::cli(),
|
||||
clippy::cli(),
|
||||
doc::cli(),
|
||||
fetch::cli(),
|
||||
fix::cli(),
|
||||
@ -43,7 +42,6 @@ pub fn builtin_exec(cmd: &str) -> Option<fn(&mut Config, &ArgMatches<'_>) -> Cli
|
||||
"build" => build::exec,
|
||||
"check" => check::exec,
|
||||
"clean" => clean::exec,
|
||||
"clippy-preview" => clippy::exec,
|
||||
"doc" => doc::exec,
|
||||
"fetch" => fetch::exec,
|
||||
"fix" => fix::exec,
|
||||
@ -80,7 +78,6 @@ pub mod bench;
|
||||
pub mod build;
|
||||
pub mod check;
|
||||
pub mod clean;
|
||||
pub mod clippy;
|
||||
pub mod doc;
|
||||
pub mod fetch;
|
||||
pub mod fix;
|
||||
|
@ -22,7 +22,7 @@ pub struct BuildConfig {
|
||||
pub force_rebuild: bool,
|
||||
/// Output a build plan to stdout instead of actually compiling.
|
||||
pub build_plan: bool,
|
||||
/// An optional override of the rustc path for primary units only
|
||||
/// An optional override of the rustc process for primary units
|
||||
pub primary_unit_rustc: Option<ProcessBuilder>,
|
||||
pub rustfix_diagnostic_server: RefCell<Option<RustfixDiagnosticServer>>,
|
||||
}
|
||||
|
@ -73,8 +73,14 @@ pub struct Compilation<'cfg> {
|
||||
pub target: String,
|
||||
|
||||
config: &'cfg Config,
|
||||
|
||||
/// Rustc process to be used by default
|
||||
rustc_process: ProcessBuilder,
|
||||
primary_unit_rustc_process: Option<ProcessBuilder>,
|
||||
/// Rustc process to be used for workspace crates instead of rustc_process
|
||||
rustc_workspace_wrapper_process: ProcessBuilder,
|
||||
/// Optional rustc process to be used for primary crates instead of either rustc_process or
|
||||
/// rustc_workspace_wrapper_process
|
||||
primary_rustc_process: Option<ProcessBuilder>,
|
||||
|
||||
target_runner: Option<(PathBuf, Vec<String>)>,
|
||||
}
|
||||
@ -85,13 +91,14 @@ impl<'cfg> Compilation<'cfg> {
|
||||
default_kind: CompileKind,
|
||||
) -> CargoResult<Compilation<'cfg>> {
|
||||
let mut rustc = bcx.rustc().process();
|
||||
|
||||
let mut primary_unit_rustc_process = bcx.build_config.primary_unit_rustc.clone();
|
||||
let mut primary_rustc_process = bcx.build_config.primary_unit_rustc.clone();
|
||||
let mut rustc_workspace_wrapper_process = bcx.rustc().workspace_process();
|
||||
|
||||
if bcx.config.extra_verbose() {
|
||||
rustc.display_env_vars();
|
||||
rustc_workspace_wrapper_process.display_env_vars();
|
||||
|
||||
if let Some(rustc) = primary_unit_rustc_process.as_mut() {
|
||||
if let Some(rustc) = primary_rustc_process.as_mut() {
|
||||
rustc.display_env_vars();
|
||||
}
|
||||
}
|
||||
@ -120,7 +127,8 @@ impl<'cfg> Compilation<'cfg> {
|
||||
rustdocflags: HashMap::new(),
|
||||
config: bcx.config,
|
||||
rustc_process: rustc,
|
||||
primary_unit_rustc_process,
|
||||
rustc_workspace_wrapper_process,
|
||||
primary_rustc_process,
|
||||
host: bcx.host_triple().to_string(),
|
||||
target: bcx.target_data.short_name(&default_kind).to_string(),
|
||||
target_runner: target_runner(bcx, default_kind)?,
|
||||
@ -128,11 +136,16 @@ impl<'cfg> Compilation<'cfg> {
|
||||
}
|
||||
|
||||
/// See `process`.
|
||||
pub fn rustc_process(&self, pkg: &Package, is_primary: bool) -> CargoResult<ProcessBuilder> {
|
||||
let rustc = if is_primary {
|
||||
self.primary_unit_rustc_process
|
||||
.clone()
|
||||
.unwrap_or_else(|| self.rustc_process.clone())
|
||||
pub fn rustc_process(
|
||||
&self,
|
||||
pkg: &Package,
|
||||
is_primary: bool,
|
||||
is_workspace: bool,
|
||||
) -> CargoResult<ProcessBuilder> {
|
||||
let rustc = if is_primary && self.primary_rustc_process.is_some() {
|
||||
self.primary_rustc_process.clone().unwrap()
|
||||
} else if is_workspace {
|
||||
self.rustc_workspace_wrapper_process.clone()
|
||||
} else {
|
||||
self.rustc_process.clone()
|
||||
};
|
||||
|
@ -616,11 +616,11 @@ fn compute_metadata<'a, 'cfg>(
|
||||
|
||||
bcx.rustc().verbose_version.hash(&mut hasher);
|
||||
|
||||
if cx.is_primary_package(unit) {
|
||||
if cx.bcx.ws.is_member(unit.pkg) {
|
||||
// This is primarily here for clippy. This ensures that the clippy
|
||||
// artifacts are separate from the `check` ones.
|
||||
if let Some(proc) = &cx.bcx.build_config.primary_unit_rustc {
|
||||
proc.get_program().hash(&mut hasher);
|
||||
if let Some(path) = &cx.bcx.rustc().workspace_wrapper {
|
||||
path.hash(&mut hasher);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1100,22 +1100,12 @@ fn calculate_normal<'a, 'cfg>(
|
||||
// Fill out a bunch more information that we'll be tracking typically
|
||||
// hashed to take up less space on disk as we just need to know when things
|
||||
// change.
|
||||
let mut extra_flags = if unit.mode.is_doc() {
|
||||
let extra_flags = if unit.mode.is_doc() {
|
||||
cx.bcx.rustdocflags_args(unit)
|
||||
} else {
|
||||
cx.bcx.rustflags_args(unit)
|
||||
}
|
||||
.to_vec();
|
||||
if cx.is_primary_package(unit) {
|
||||
// This is primarily here for clippy arguments.
|
||||
if let Some(proc) = &cx.bcx.build_config.primary_unit_rustc {
|
||||
let args = proc
|
||||
.get_args()
|
||||
.iter()
|
||||
.map(|s| s.to_string_lossy().to_string());
|
||||
extra_flags.extend(args);
|
||||
}
|
||||
}
|
||||
|
||||
let profile_hash = util::hash_u64((&unit.profile, unit.mode, cx.bcx.extra_args_for(unit)));
|
||||
// Include metadata since it is exposed as environment variables.
|
||||
|
@ -538,8 +538,11 @@ fn prepare_rustc<'a, 'cfg>(
|
||||
unit: &Unit<'a>,
|
||||
) -> CargoResult<ProcessBuilder> {
|
||||
let is_primary = cx.is_primary_package(unit);
|
||||
let is_workspace = cx.bcx.ws.is_member(unit.pkg);
|
||||
|
||||
let mut base = cx.compilation.rustc_process(unit.pkg, is_primary)?;
|
||||
let mut base = cx
|
||||
.compilation
|
||||
.rustc_process(unit.pkg, is_primary, is_workspace)?;
|
||||
if cx.bcx.config.cli_unstable().jobserver_per_rustc {
|
||||
let client = cx.new_jobserver()?;
|
||||
base.inherit_jobserver(&client);
|
||||
|
@ -53,9 +53,10 @@ use rustfix::{self, CodeFix};
|
||||
|
||||
use crate::core::Workspace;
|
||||
use crate::ops::{self, CompileOptions};
|
||||
use crate::util;
|
||||
use crate::util::diagnostic_server::{Message, RustfixDiagnosticServer};
|
||||
use crate::util::errors::CargoResult;
|
||||
use crate::util::{self, paths};
|
||||
use crate::util::ProcessBuilder;
|
||||
use crate::util::{existing_vcs_repo, LockServer, LockServerClient};
|
||||
|
||||
const FIX_ENV: &str = "__CARGO_FIX_PLZ";
|
||||
@ -63,7 +64,6 @@ const BROKEN_CODE_ENV: &str = "__CARGO_FIX_BROKEN_CODE";
|
||||
const PREPARE_FOR_ENV: &str = "__CARGO_FIX_PREPARE_FOR";
|
||||
const EDITION_ENV: &str = "__CARGO_FIX_EDITION";
|
||||
const IDIOMS_ENV: &str = "__CARGO_FIX_IDIOMS";
|
||||
const CLIPPY_FIX_ARGS: &str = "__CARGO_FIX_CLIPPY_ARGS";
|
||||
|
||||
pub struct FixOptions<'a> {
|
||||
pub edition: bool,
|
||||
@ -74,7 +74,6 @@ pub struct FixOptions<'a> {
|
||||
pub allow_no_vcs: bool,
|
||||
pub allow_staged: bool,
|
||||
pub broken_code: bool,
|
||||
pub clippy_args: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
pub fn fix(ws: &Workspace<'_>, opts: &mut FixOptions<'_>) -> CargoResult<()> {
|
||||
@ -101,19 +100,6 @@ pub fn fix(ws: &Workspace<'_>, opts: &mut FixOptions<'_>) -> CargoResult<()> {
|
||||
wrapper.env(IDIOMS_ENV, "1");
|
||||
}
|
||||
|
||||
if opts.clippy_args.is_some() {
|
||||
if let Err(e) = util::process("clippy-driver").arg("-V").exec_with_output() {
|
||||
eprintln!("Warning: clippy-driver not found: {:?}", e);
|
||||
}
|
||||
|
||||
let clippy_args = opts
|
||||
.clippy_args
|
||||
.as_ref()
|
||||
.map_or_else(String::new, |args| serde_json::to_string(&args).unwrap());
|
||||
|
||||
wrapper.env(CLIPPY_FIX_ARGS, clippy_args);
|
||||
}
|
||||
|
||||
*opts
|
||||
.compile_opts
|
||||
.build_config
|
||||
@ -222,12 +208,17 @@ pub fn fix_maybe_exec_rustc() -> CargoResult<bool> {
|
||||
|
||||
let args = FixArgs::get();
|
||||
trace!("cargo-fix as rustc got file {:?}", args.file);
|
||||
|
||||
let rustc = args.rustc.as_ref().expect("fix wrapper rustc was not set");
|
||||
let workspace_rustc = std::env::var("RUSTC_WORKSPACE_WRAPPER")
|
||||
.map(PathBuf::from)
|
||||
.ok();
|
||||
let rustc = util::process(rustc).wrapped(workspace_rustc.as_ref());
|
||||
|
||||
let mut fixes = FixedCrate::default();
|
||||
if let Some(path) = &args.file {
|
||||
trace!("start rustfixing {:?}", path);
|
||||
fixes = rustfix_crate(&lock_addr, rustc.as_ref(), path, &args)?;
|
||||
fixes = rustfix_crate(&lock_addr, &rustc, path, &args)?;
|
||||
}
|
||||
|
||||
// Ok now we have our final goal of testing out the changes that we applied.
|
||||
@ -239,7 +230,7 @@ pub fn fix_maybe_exec_rustc() -> CargoResult<bool> {
|
||||
// new rustc, and otherwise we capture the output to hide it in the scenario
|
||||
// that we have to back it all out.
|
||||
if !fixes.files.is_empty() {
|
||||
let mut cmd = Command::new(&rustc);
|
||||
let mut cmd = rustc.build_command();
|
||||
args.apply(&mut cmd);
|
||||
cmd.arg("--error-format=json");
|
||||
let output = cmd.output().context("failed to spawn rustc")?;
|
||||
@ -279,7 +270,7 @@ pub fn fix_maybe_exec_rustc() -> CargoResult<bool> {
|
||||
// - If the fix failed, show the original warnings and suggestions.
|
||||
// - If `--broken-code`, show the error messages.
|
||||
// - If the fix succeeded, show any remaining warnings.
|
||||
let mut cmd = Command::new(&rustc);
|
||||
let mut cmd = rustc.build_command();
|
||||
args.apply(&mut cmd);
|
||||
for arg in args.format_args {
|
||||
// Add any json/error format arguments that Cargo wants. This allows
|
||||
@ -302,7 +293,7 @@ struct FixedFile {
|
||||
|
||||
fn rustfix_crate(
|
||||
lock_addr: &str,
|
||||
rustc: &Path,
|
||||
rustc: &ProcessBuilder,
|
||||
filename: &Path,
|
||||
args: &FixArgs,
|
||||
) -> Result<FixedCrate, Error> {
|
||||
@ -402,7 +393,7 @@ fn rustfix_crate(
|
||||
/// and any errors encountered while fixing files.
|
||||
fn rustfix_and_fix(
|
||||
fixes: &mut FixedCrate,
|
||||
rustc: &Path,
|
||||
rustc: &ProcessBuilder,
|
||||
filename: &Path,
|
||||
args: &FixArgs,
|
||||
) -> Result<(), Error> {
|
||||
@ -410,12 +401,15 @@ fn rustfix_and_fix(
|
||||
// TODO: implement a way to specify this.
|
||||
let only = HashSet::new();
|
||||
|
||||
let mut cmd = Command::new(rustc);
|
||||
let mut cmd = rustc.build_command();
|
||||
cmd.arg("--error-format=json");
|
||||
args.apply(&mut cmd);
|
||||
let output = cmd
|
||||
.output()
|
||||
.with_context(|| format!("failed to execute `{}`", rustc.display()))?;
|
||||
let output = cmd.output().with_context(|| {
|
||||
format!(
|
||||
"failed to execute `{}`",
|
||||
rustc.get_program().to_string_lossy()
|
||||
)
|
||||
})?;
|
||||
|
||||
// If rustc didn't succeed for whatever reasons then we're very likely to be
|
||||
// looking at otherwise broken code. Let's not make things accidentally
|
||||
@ -491,7 +485,7 @@ fn rustfix_and_fix(
|
||||
// Attempt to read the source code for this file. If this fails then
|
||||
// that'd be pretty surprising, so log a message and otherwise keep
|
||||
// going.
|
||||
let code = match paths::read(file.as_ref()) {
|
||||
let code = match util::paths::read(file.as_ref()) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
warn!("failed to read `{}`: {}", file, e);
|
||||
@ -591,7 +585,6 @@ struct FixArgs {
|
||||
enabled_edition: Option<String>,
|
||||
other: Vec<OsString>,
|
||||
rustc: Option<PathBuf>,
|
||||
clippy_args: Vec<String>,
|
||||
format_args: Vec<String>,
|
||||
}
|
||||
|
||||
@ -611,12 +604,7 @@ impl FixArgs {
|
||||
fn get() -> FixArgs {
|
||||
let mut ret = FixArgs::default();
|
||||
|
||||
if let Ok(clippy_args) = env::var(CLIPPY_FIX_ARGS) {
|
||||
ret.clippy_args = serde_json::from_str(&clippy_args).unwrap();
|
||||
ret.rustc = Some(util::config::clippy_driver());
|
||||
} else {
|
||||
ret.rustc = env::args_os().nth(1).map(PathBuf::from);
|
||||
}
|
||||
ret.rustc = env::args_os().nth(1).map(PathBuf::from);
|
||||
|
||||
for arg in env::args_os().skip(2) {
|
||||
let path = PathBuf::from(arg);
|
||||
@ -654,10 +642,6 @@ impl FixArgs {
|
||||
cmd.arg(path);
|
||||
}
|
||||
|
||||
if !self.clippy_args.is_empty() {
|
||||
cmd.args(&self.clippy_args);
|
||||
}
|
||||
|
||||
cmd.args(&self.other).arg("--cap-lints=warn");
|
||||
if let Some(edition) = &self.enabled_edition {
|
||||
cmd.arg("--edition").arg(edition);
|
||||
|
@ -314,9 +314,19 @@ impl Config {
|
||||
.into_path_unlocked()
|
||||
});
|
||||
let wrapper = self.maybe_get_tool("rustc_wrapper", &self.build_config()?.rustc_wrapper);
|
||||
let rustc_workspace_wrapper = self.maybe_get_tool(
|
||||
"rustc_workspace_wrapper",
|
||||
&self.build_config()?.rustc_workspace_wrapper,
|
||||
);
|
||||
|
||||
if !self.cli_unstable().unstable_options && rustc_workspace_wrapper.is_some() {
|
||||
bail!("Usage of `RUSTC_WORKSPACE_WRAPPER` requires `-Z unstable-options`")
|
||||
}
|
||||
|
||||
Rustc::new(
|
||||
self.get_tool("rustc", &self.build_config()?.rustc),
|
||||
wrapper,
|
||||
rustc_workspace_wrapper,
|
||||
&self
|
||||
.home()
|
||||
.join("bin")
|
||||
@ -1645,15 +1655,6 @@ impl Drop for PackageCacheLock<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
/// returns path to clippy-driver binary
|
||||
///
|
||||
/// Allows override of the path via `CARGO_CLIPPY_DRIVER` env variable
|
||||
pub fn clippy_driver() -> PathBuf {
|
||||
env::var("CARGO_CLIPPY_DRIVER")
|
||||
.unwrap_or_else(|_| "clippy-driver".into())
|
||||
.into()
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct CargoHttpConfig {
|
||||
@ -1714,6 +1715,7 @@ pub struct CargoBuildConfig {
|
||||
pub rustflags: Option<StringList>,
|
||||
pub rustdocflags: Option<StringList>,
|
||||
pub rustc_wrapper: Option<PathBuf>,
|
||||
pub rustc_workspace_wrapper: Option<PathBuf>,
|
||||
pub rustc: Option<PathBuf>,
|
||||
pub rustdoc: Option<PathBuf>,
|
||||
pub out_dir: Option<ConfigRelativePath>,
|
||||
|
@ -6,6 +6,7 @@ use std::collections::BTreeMap;
|
||||
use std::env;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::fmt;
|
||||
use std::iter::once;
|
||||
use std::path::Path;
|
||||
use std::process::{Command, Output, Stdio};
|
||||
|
||||
@ -326,6 +327,37 @@ impl ProcessBuilder {
|
||||
}
|
||||
command
|
||||
}
|
||||
|
||||
/// Wraps an existing command with the provided wrapper, if it is present and valid.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use cargo::util::{ProcessBuilder, process};
|
||||
/// // Running this would execute `rustc`
|
||||
/// let cmd: ProcessBuilder = process("rustc");
|
||||
///
|
||||
/// // Running this will execute `sccache rustc`
|
||||
/// let cmd = cmd.wrapped(Some("sccache"));
|
||||
/// ```
|
||||
pub fn wrapped(mut self, wrapper: Option<impl AsRef<OsStr>>) -> Self {
|
||||
let wrapper = if let Some(wrapper) = wrapper.as_ref() {
|
||||
wrapper.as_ref()
|
||||
} else {
|
||||
return self;
|
||||
};
|
||||
|
||||
if wrapper.is_empty() {
|
||||
return self;
|
||||
}
|
||||
|
||||
let args = once(self.program).chain(self.args.into_iter()).collect();
|
||||
|
||||
self.program = wrapper.to_os_string();
|
||||
self.args = args;
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper function to create a `ProcessBuilder`.
|
||||
|
@ -20,7 +20,9 @@ pub struct Rustc {
|
||||
pub path: PathBuf,
|
||||
/// An optional program that will be passed the path of the rust exe as its first argument, and
|
||||
/// rustc args following this.
|
||||
pub wrapper: Option<ProcessBuilder>,
|
||||
pub wrapper: Option<PathBuf>,
|
||||
/// An optional wrapper to be used in addition to `rustc.wrapper` for workspace crates
|
||||
pub workspace_wrapper: Option<PathBuf>,
|
||||
/// Verbose version information (the output of `rustc -vV`)
|
||||
pub verbose_version: String,
|
||||
/// The host triple (arch-platform-OS), this comes from verbose_version.
|
||||
@ -37,6 +39,7 @@ impl Rustc {
|
||||
pub fn new(
|
||||
path: PathBuf,
|
||||
wrapper: Option<PathBuf>,
|
||||
workspace_wrapper: Option<PathBuf>,
|
||||
rustup_rustc: &Path,
|
||||
cache_location: Option<PathBuf>,
|
||||
) -> CargoResult<Rustc> {
|
||||
@ -64,7 +67,8 @@ impl Rustc {
|
||||
|
||||
Ok(Rustc {
|
||||
path,
|
||||
wrapper: wrapper.map(util::process),
|
||||
wrapper,
|
||||
workspace_wrapper,
|
||||
verbose_version,
|
||||
host,
|
||||
cache: Mutex::new(cache),
|
||||
@ -72,20 +76,15 @@ impl Rustc {
|
||||
}
|
||||
|
||||
/// Gets a process builder set up to use the found rustc version, with a wrapper if `Some`.
|
||||
pub fn process_with(&self, path: impl AsRef<Path>) -> ProcessBuilder {
|
||||
match self.wrapper {
|
||||
Some(ref wrapper) if !wrapper.get_program().is_empty() => {
|
||||
let mut cmd = wrapper.clone();
|
||||
cmd.arg(path.as_ref());
|
||||
cmd
|
||||
}
|
||||
_ => util::process(path.as_ref()),
|
||||
}
|
||||
pub fn process(&self) -> ProcessBuilder {
|
||||
util::process(self.path.as_path()).wrapped(self.wrapper.as_ref())
|
||||
}
|
||||
|
||||
/// Gets a process builder set up to use the found rustc version, with a wrapper if `Some`.
|
||||
pub fn process(&self) -> ProcessBuilder {
|
||||
self.process_with(&self.path)
|
||||
pub fn workspace_process(&self) -> ProcessBuilder {
|
||||
util::process(self.path.as_path())
|
||||
.wrapped(self.workspace_wrapper.as_ref())
|
||||
.wrapped(self.wrapper.as_ref())
|
||||
}
|
||||
|
||||
pub fn process_no_wrapper(&self) -> ProcessBuilder {
|
||||
@ -95,10 +94,6 @@ impl Rustc {
|
||||
pub fn cached_output(&self, cmd: &ProcessBuilder) -> CargoResult<(String, String)> {
|
||||
self.cache.lock().unwrap().cached_output(cmd)
|
||||
}
|
||||
|
||||
pub fn set_wrapper(&mut self, wrapper: ProcessBuilder) {
|
||||
self.wrapper = Some(wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
/// It is a well known fact that `rustc` is not the fastest compiler in the
|
||||
|
@ -3700,6 +3700,42 @@ fn rustc_wrapper_from_path() {
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
// NOTE: we don't have `/usr/bin/env` on Windows.
|
||||
#[cfg(not(windows))]
|
||||
fn rustc_workspace_wrapper() {
|
||||
let p = project().file("src/lib.rs", "").build();
|
||||
p.cargo("build -v -Zunstable-options")
|
||||
.env("RUSTC_WORKSPACE_WRAPPER", "/usr/bin/env")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stderr_contains("[RUNNING] `/usr/bin/env rustc --crate-name foo [..]")
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
#[cfg(not(windows))]
|
||||
fn rustc_workspace_wrapper_relative() {
|
||||
let p = project().file("src/lib.rs", "").build();
|
||||
p.cargo("build -v -Zunstable-options")
|
||||
.env("RUSTC_WORKSPACE_WRAPPER", "./sccache")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_status(101)
|
||||
.with_stderr_contains("[..]/foo/./sccache rustc[..]")
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
#[cfg(not(windows))]
|
||||
fn rustc_workspace_wrapper_from_path() {
|
||||
let p = project().file("src/lib.rs", "").build();
|
||||
p.cargo("build -v -Zunstable-options")
|
||||
.env("RUSTC_WORKSPACE_WRAPPER", "wannabe_sccache")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_status(101)
|
||||
.with_stderr_contains("[..]`wannabe_sccache rustc [..]")
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn cdylib_not_lifted() {
|
||||
let p = project()
|
||||
|
@ -1,8 +1,7 @@
|
||||
//! Tests for caching compiler diagnostics.
|
||||
|
||||
use cargo_test_support::{
|
||||
basic_manifest, command_is_available, is_coarse_mtime, process, project, registry::Package,
|
||||
sleep_ms,
|
||||
basic_manifest, is_coarse_mtime, process, project, registry::Package, sleep_ms,
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
@ -274,56 +273,6 @@ fn fix() {
|
||||
assert_eq!(p.read_file("src/lib.rs"), "pub fn r#try() {}");
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn clippy() {
|
||||
if !command_is_available("clippy-driver") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Caching clippy output.
|
||||
// This is just a random clippy lint (assertions_on_constants) that
|
||||
// hopefully won't change much in the future.
|
||||
let p = project()
|
||||
.file(
|
||||
"src/lib.rs",
|
||||
"pub fn f() { assert!(true); }\n\
|
||||
fn unused_func() {}",
|
||||
)
|
||||
.build();
|
||||
|
||||
p.cargo("clippy-preview -Zunstable-options -v")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stderr_contains("[RUNNING] `clippy[..]")
|
||||
.with_stderr_contains("[..]assert!(true)[..]")
|
||||
.run();
|
||||
|
||||
// `check` should be separate from clippy.
|
||||
p.cargo("check -v")
|
||||
.with_stderr_contains(
|
||||
"\
|
||||
[CHECKING] foo [..]
|
||||
[RUNNING] `rustc[..]
|
||||
[WARNING] [..]unused_func[..]
|
||||
",
|
||||
)
|
||||
.with_stderr_does_not_contain("[..]assert!(true)[..]")
|
||||
.run();
|
||||
|
||||
// Again, reading from the cache.
|
||||
p.cargo("clippy-preview -Zunstable-options -v")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stderr_contains("[FRESH] foo [..]")
|
||||
.with_stderr_contains("[..]assert!(true)[..]")
|
||||
.run();
|
||||
|
||||
// And `check` should also be fresh, reading from cache.
|
||||
p.cargo("check -v")
|
||||
.with_stderr_contains("[FRESH] foo [..]")
|
||||
.with_stderr_contains("[WARNING] [..]unused_func[..]")
|
||||
.with_stderr_does_not_contain("[..]assert!(true)[..]")
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn very_verbose() {
|
||||
// Handle cap-lints in dependencies.
|
||||
@ -496,3 +445,50 @@ fn caching_large_output() {
|
||||
))
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
#[cfg(unix)]
|
||||
fn rustc_workspace_wrapper() {
|
||||
use cargo_test_support::paths;
|
||||
|
||||
let p = project()
|
||||
.file(
|
||||
"src/lib.rs",
|
||||
"pub fn f() { assert!(true); }\n\
|
||||
fn unused_func() {}",
|
||||
)
|
||||
.build();
|
||||
|
||||
p.cargo("check -Zunstable-options -v")
|
||||
.env("RUSTC_WORKSPACE_WRAPPER", paths::echo_wrapper().unwrap())
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stdout_contains("WRAPPER CALLED: rustc --crate-name foo src/lib.rs [..]")
|
||||
.run();
|
||||
|
||||
// Check without a wrapper should rebuild
|
||||
p.cargo("check -v")
|
||||
.with_stderr_contains(
|
||||
"\
|
||||
[CHECKING] foo [..]
|
||||
[RUNNING] `rustc[..]
|
||||
[WARNING] [..]unused_func[..]
|
||||
",
|
||||
)
|
||||
.with_stdout_does_not_contain("WRAPPER CALLED: rustc --crate-name foo src/lib.rs [..]")
|
||||
.run();
|
||||
|
||||
// Again, reading from the cache.
|
||||
p.cargo("check -Zunstable-options -v")
|
||||
.env("RUSTC_WORKSPACE_WRAPPER", paths::echo_wrapper().unwrap())
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stderr_contains("[FRESH] foo [..]")
|
||||
.with_stdout_does_not_contain("WRAPPER CALLED: rustc --crate-name foo src/lib.rs [..]")
|
||||
.run();
|
||||
|
||||
// And `check` should also be fresh, reading from cache.
|
||||
p.cargo("check -v")
|
||||
.with_stderr_contains("[FRESH] foo [..]")
|
||||
.with_stderr_contains("[WARNING] [..]unused_func[..]")
|
||||
.with_stdout_does_not_contain("WRAPPER CALLED: rustc --crate-name foo src/lib.rs [..]")
|
||||
.run();
|
||||
}
|
||||
|
@ -752,6 +752,15 @@ fn does_not_use_empty_rustc_wrapper() {
|
||||
p.cargo("check").env("RUSTC_WRAPPER", "").run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn does_not_use_empty_rustc_workspace_wrapper() {
|
||||
let p = project().file("src/lib.rs", "").build();
|
||||
p.cargo("check -Zunstable-options")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.env("RUSTC_WORKSPACE_WRAPPER", "")
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn error_from_deep_recursion() -> Result<(), fmt::Error> {
|
||||
let mut big_macro = String::new();
|
||||
@ -772,3 +781,128 @@ fn error_from_deep_recursion() -> Result<(), fmt::Error> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
#[cfg(unix)]
|
||||
fn rustc_workspace_wrapper_affects_all_workspace_members() {
|
||||
use cargo_test_support::paths;
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[workspace]
|
||||
members = ["bar", "baz"]
|
||||
"#,
|
||||
)
|
||||
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
|
||||
.file("bar/src/lib.rs", "pub fn bar() {}")
|
||||
.file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
|
||||
.file("baz/src/lib.rs", "pub fn baz() {}")
|
||||
.build();
|
||||
|
||||
p.cargo("check -Zunstable-options")
|
||||
.env("RUSTC_WORKSPACE_WRAPPER", paths::echo_wrapper().unwrap())
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stdout_contains("WRAPPER CALLED: rustc --crate-name bar [..]")
|
||||
.with_stdout_contains("WRAPPER CALLED: rustc --crate-name baz [..]")
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
#[cfg(unix)]
|
||||
fn rustc_workspace_wrapper_includes_path_deps() {
|
||||
use cargo_test_support::paths;
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[project]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
authors = []
|
||||
|
||||
[workspace]
|
||||
members = ["bar"]
|
||||
|
||||
[dependencies]
|
||||
baz = { path = "baz" }
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
|
||||
.file("bar/src/lib.rs", "pub fn bar() {}")
|
||||
.file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
|
||||
.file("baz/src/lib.rs", "pub fn baz() {}")
|
||||
.build();
|
||||
|
||||
p.cargo("check --workspace -Zunstable-options")
|
||||
.env("RUSTC_WORKSPACE_WRAPPER", paths::echo_wrapper().unwrap())
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stdout_contains("WRAPPER CALLED: rustc --crate-name foo [..]")
|
||||
.with_stdout_contains("WRAPPER CALLED: rustc --crate-name bar [..]")
|
||||
.with_stdout_contains("WRAPPER CALLED: rustc --crate-name baz [..]")
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
#[cfg(unix)]
|
||||
fn rustc_workspace_wrapper_respects_primary_units() {
|
||||
use cargo_test_support::paths;
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[workspace]
|
||||
members = ["bar", "baz"]
|
||||
"#,
|
||||
)
|
||||
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
|
||||
.file("bar/src/lib.rs", "pub fn bar() {}")
|
||||
.file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
|
||||
.file("baz/src/lib.rs", "pub fn baz() {}")
|
||||
.build();
|
||||
|
||||
p.cargo("check -p bar -Zunstable-options")
|
||||
.env("RUSTC_WORKSPACE_WRAPPER", paths::echo_wrapper().unwrap())
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stdout_contains("WRAPPER CALLED: rustc --crate-name bar [..]")
|
||||
.with_stdout_does_not_contain("WRAPPER CALLED: rustc --crate-name baz [..]")
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
#[cfg(unix)]
|
||||
fn rustc_workspace_wrapper_excludes_published_deps() {
|
||||
use cargo_test_support::paths;
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[project]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
authors = []
|
||||
|
||||
[workspace]
|
||||
members = ["bar"]
|
||||
|
||||
[dependencies]
|
||||
baz = "1.0.0"
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
|
||||
.file("bar/src/lib.rs", "pub fn bar() {}")
|
||||
.build();
|
||||
|
||||
Package::new("baz", "1.0.0").publish();
|
||||
|
||||
p.cargo("check --workspace -v -Zunstable-options")
|
||||
.env("RUSTC_WORKSPACE_WRAPPER", paths::echo_wrapper().unwrap())
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stdout_contains("WRAPPER CALLED: rustc --crate-name foo [..]")
|
||||
.with_stdout_contains("WRAPPER CALLED: rustc --crate-name bar [..]")
|
||||
.with_stderr_contains("[CHECKING] baz [..]")
|
||||
.with_stdout_does_not_contain("WRAPPER CALLED: rustc --crate-name baz [..]")
|
||||
.run();
|
||||
}
|
||||
|
@ -3,7 +3,9 @@
|
||||
use std::fs::File;
|
||||
|
||||
use cargo_test_support::git;
|
||||
use cargo_test_support::{basic_manifest, command_is_available, project};
|
||||
#[cfg(unix)]
|
||||
use cargo_test_support::paths;
|
||||
use cargo_test_support::{basic_manifest, project};
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
@ -1068,11 +1070,8 @@ fn doesnt_rebuild_dependencies() {
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
#[cfg(unix)]
|
||||
fn does_not_crash_with_rustc_wrapper() {
|
||||
// We don't have /usr/bin/env on Windows.
|
||||
if cfg!(windows) {
|
||||
return;
|
||||
}
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
@ -1090,6 +1089,50 @@ fn does_not_crash_with_rustc_wrapper() {
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
#[cfg(unix)]
|
||||
fn does_not_crash_with_rustc_workspace_wrapper() {
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("fix --allow-no-vcs --verbose -Zunstable-options")
|
||||
.env("RUSTC_WORKSPACE_WRAPPER", "/usr/bin/env")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
#[cfg(unix)]
|
||||
fn uses_workspace_wrapper_and_primary_wrapper_override() {
|
||||
// We don't have /usr/bin/env on Windows.
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("fix --allow-no-vcs --verbose -Zunstable-options")
|
||||
.env("RUSTC_WORKSPACE_WRAPPER", paths::echo_wrapper().unwrap())
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stdout_contains("WRAPPER CALLED: rustc src/lib.rs --crate-name foo [..]")
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn only_warn_for_relevant_crates() {
|
||||
let p = project()
|
||||
@ -1251,47 +1294,6 @@ fn fix_in_existing_repo_weird_ignore() {
|
||||
p.cargo("fix").cwd("src").run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn fix_with_clippy() {
|
||||
if !command_is_available("clippy-driver") {
|
||||
return;
|
||||
}
|
||||
|
||||
let p = project()
|
||||
.file(
|
||||
"src/lib.rs",
|
||||
"
|
||||
pub fn foo() {
|
||||
let mut v = Vec::<String>::new();
|
||||
let _ = v.iter_mut().filter(|&ref a| a.is_empty());
|
||||
}
|
||||
",
|
||||
)
|
||||
.build();
|
||||
|
||||
let stderr = "\
|
||||
[CHECKING] foo v0.0.1 ([..])
|
||||
[FIXING] src/lib.rs (1 fix)
|
||||
[FINISHED] [..]
|
||||
";
|
||||
|
||||
p.cargo("fix -Zunstable-options --clippy --allow-no-vcs")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stderr(stderr)
|
||||
.with_stdout("")
|
||||
.run();
|
||||
|
||||
assert_eq!(
|
||||
p.read_file("src/lib.rs"),
|
||||
"
|
||||
pub fn foo() {
|
||||
let mut v = Vec::<String>::new();
|
||||
let _ = v.iter_mut().filter(|a| a.is_empty());
|
||||
}
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn fix_color_message() {
|
||||
// Check that color appears in diagnostics.
|
||||
|
@ -28,7 +28,6 @@ mod cargo_targets;
|
||||
mod cfg;
|
||||
mod check;
|
||||
mod clean;
|
||||
mod clippy;
|
||||
mod collisions;
|
||||
mod concurrent;
|
||||
mod config;
|
||||
|
Loading…
x
Reference in New Issue
Block a user