Skip to content

Commit 1e5cac7

Browse files
committed
Auto merge of #10413 - ehuss:beta-fix-rustflags-gate, r=alexcrichton
[beta] Add common profile validation. Beta backport of: * #10411 — This is intended to limit any potential misuse of rustflags in profiles. * #10396 — Fix CI due to clap deprecation
2 parents ea2a21c + 0ebfe2e commit 1e5cac7

File tree

13 files changed

+107
-49
lines changed

13 files changed

+107
-49
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ toml_edit = { version = "0.13.4", features = ["serde", "easy"] }
6161
unicode-xid = "0.2.0"
6262
url = "2.2.2"
6363
walkdir = "2.2"
64-
clap = "3.0.13"
64+
clap = "3.1.0"
6565
unicode-width = "0.1.5"
6666
openssl = { version = '0.10.11', optional = true }
6767
im-rc = "15.0.0"

src/bin/cargo/cli.rs

+18-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use anyhow::anyhow;
22
use cargo::core::{features, CliUnstable};
33
use cargo::{self, drop_print, drop_println, CliResult, Config};
4-
use clap::{AppSettings, Arg, ArgMatches};
4+
use clap::{
5+
error::{ContextKind, ContextValue},
6+
AppSettings, Arg, ArgMatches,
7+
};
58
use itertools::Itertools;
69
use std::collections::HashMap;
710
use std::fmt::Write;
@@ -33,9 +36,17 @@ pub fn main(config: &mut Config) -> CliResult {
3336
let args = match cli().try_get_matches() {
3437
Ok(args) => args,
3538
Err(e) => {
36-
if e.kind == clap::ErrorKind::UnrecognizedSubcommand {
39+
if e.kind() == clap::ErrorKind::UnrecognizedSubcommand {
3740
// An unrecognized subcommand might be an external subcommand.
38-
let cmd = e.info[0].clone();
41+
let cmd = e
42+
.context()
43+
.find_map(|c| match c {
44+
(ContextKind::InvalidSubcommand, &ContextValue::String(ref cmd)) => {
45+
Some(cmd)
46+
}
47+
_ => None,
48+
})
49+
.expect("UnrecognizedSubcommand implies the presence of InvalidSubcommand");
3950
return super::execute_external_subcommand(config, &cmd, &[&cmd, "--help"])
4051
.map_err(|_| e.into());
4152
} else {
@@ -286,9 +297,7 @@ For more information, see issue #10049 <https://github.com/rust-lang/cargo/issue
286297
// Note that an alias to an external command will not receive
287298
// these arguments. That may be confusing, but such is life.
288299
let global_args = GlobalArgs::new(args);
289-
let new_args = cli()
290-
.setting(AppSettings::NoBinaryName)
291-
.try_get_matches_from(alias)?;
300+
let new_args = cli().no_binary_name(true).try_get_matches_from(alias)?;
292301

293302
let new_cmd = new_args.subcommand_name().expect("subcommand is required");
294303
already_expanded.push(cmd.to_string());
@@ -406,14 +415,11 @@ fn cli() -> App {
406415
"cargo [OPTIONS] [SUBCOMMAND]"
407416
};
408417
App::new("cargo")
409-
.setting(
410-
AppSettings::DeriveDisplayOrder
411-
| AppSettings::AllowExternalSubcommands
412-
| AppSettings::NoAutoVersion,
413-
)
418+
.allow_external_subcommands(true)
419+
.setting(AppSettings::DeriveDisplayOrder | AppSettings::NoAutoVersion)
414420
// Doesn't mix well with our list of common cargo commands. See clap-rs/clap#3108 for
415421
// opening clap up to allow us to style our help template
416-
.global_setting(AppSettings::DisableColoredHelp)
422+
.disable_colored_help(true)
417423
.override_usage(usage)
418424
.help_template(
419425
"\

src/bin/cargo/commands/bench.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use cargo::ops::{self, TestOptions};
33

44
pub fn cli() -> App {
55
subcommand("bench")
6-
.setting(AppSettings::TrailingVarArg)
6+
.trailing_var_arg(true)
77
.about("Execute all benchmarks of a local package")
88
.arg_quiet()
99
.arg(

src/bin/cargo/commands/config.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ pub fn cli() -> App {
55
subcommand("config")
66
.about("Inspect configuration values")
77
.after_help("Run `cargo help config` for more detailed information.\n")
8-
.setting(clap::AppSettings::SubcommandRequiredElseHelp)
8+
.subcommand_required(true)
9+
.arg_required_else_help(true)
910
.subcommand(
1011
subcommand("get")
1112
.arg(Arg::new("key").help("The config key to display"))

src/bin/cargo/commands/git_checkout.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const REMOVED: &str = "The `git-checkout` subcommand has been removed.";
55
pub fn cli() -> App {
66
subcommand("git-checkout")
77
.about("This subcommand has been removed")
8-
.setting(AppSettings::Hidden)
8+
.hide(true)
99
.override_help(REMOVED)
1010
}
1111

src/bin/cargo/commands/report.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ pub fn cli() -> App {
66
subcommand("report")
77
.about("Generate and display various kinds of reports")
88
.after_help("Run `cargo help report` for more detailed information.\n")
9-
.setting(clap::AppSettings::SubcommandRequiredElseHelp)
9+
.subcommand_required(true)
10+
.arg_required_else_help(true)
1011
.subcommand(
1112
subcommand("future-incompatibilities")
1213
.alias("future-incompat")

src/bin/cargo/commands/run.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub fn cli() -> App {
88
subcommand("run")
99
// subcommand aliases are handled in aliased_command()
1010
// .alias("r")
11-
.setting(AppSettings::TrailingVarArg)
11+
.trailing_var_arg(true)
1212
.about("Run a binary or example of the local package")
1313
.arg_quiet()
1414
.arg(

src/bin/cargo/commands/rustc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const CRATE_TYPE_ARG_NAME: &str = "crate-type";
77

88
pub fn cli() -> App {
99
subcommand("rustc")
10-
.setting(AppSettings::TrailingVarArg)
10+
.trailing_var_arg(true)
1111
.about("Compile a package, and pass extra options to the compiler")
1212
.arg_quiet()
1313
.arg(Arg::new("args").multiple_values(true).help("Rustc flags"))

src/bin/cargo/commands/rustdoc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::command_prelude::*;
44

55
pub fn cli() -> App {
66
subcommand("rustdoc")
7-
.setting(AppSettings::TrailingVarArg)
7+
.trailing_var_arg(true)
88
.about("Build a package's documentation, using specified custom flags.")
99
.arg_quiet()
1010
.arg(Arg::new("args").multiple_values(true))

src/bin/cargo/commands/test.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub fn cli() -> App {
66
subcommand("test")
77
// Subcommand aliases are handled in `aliased_command()`.
88
// .alias("t")
9-
.setting(AppSettings::TrailingVarArg)
9+
.trailing_var_arg(true)
1010
.about("Execute all unit and integration tests and build examples of a local package")
1111
.arg(
1212
Arg::new("TESTNAME")

src/cargo/util/command_prelude.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub use crate::core::compiler::CompileMode;
2222
pub use crate::{CliError, CliResult, Config};
2323
pub use clap::{AppSettings, Arg, ArgMatches};
2424

25-
pub type App = clap::App<'static>;
25+
pub type App = clap::Command<'static>;
2626

2727
pub trait AppExt: Sized {
2828
fn _arg(self, arg: Arg<'static>) -> Self;
@@ -281,7 +281,9 @@ pub fn multi_opt(name: &'static str, value_name: &'static str, help: &'static st
281281
}
282282

283283
pub fn subcommand(name: &'static str) -> App {
284-
App::new(name).setting(AppSettings::DeriveDisplayOrder | AppSettings::DontCollapseArgsInUsage)
284+
App::new(name)
285+
.dont_collapse_args_in_usage(true)
286+
.setting(AppSettings::DeriveDisplayOrder)
285287
}
286288

287289
/// Determines whether or not to gate `--profile` as unstable when resolving it.

src/cargo/util/toml/mod.rs

+38-26
Original file line numberDiff line numberDiff line change
@@ -448,10 +448,7 @@ impl ser::Serialize for ProfilePackageSpec {
448448
where
449449
S: ser::Serializer,
450450
{
451-
match *self {
452-
ProfilePackageSpec::Spec(ref spec) => spec.serialize(s),
453-
ProfilePackageSpec::All => "*".serialize(s),
454-
}
451+
self.to_string().serialize(s)
455452
}
456453
}
457454

@@ -471,21 +468,33 @@ impl<'de> de::Deserialize<'de> for ProfilePackageSpec {
471468
}
472469
}
473470

471+
impl fmt::Display for ProfilePackageSpec {
472+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
473+
match self {
474+
ProfilePackageSpec::Spec(spec) => spec.fmt(f),
475+
ProfilePackageSpec::All => f.write_str("*"),
476+
}
477+
}
478+
}
479+
474480
impl TomlProfile {
475481
pub fn validate(
476482
&self,
477483
name: &str,
478484
features: &Features,
479485
warnings: &mut Vec<String>,
480486
) -> CargoResult<()> {
487+
self.validate_profile(name, features)?;
481488
if let Some(ref profile) = self.build_override {
482489
features.require(Feature::profile_overrides())?;
483-
profile.validate_override("build-override", features)?;
490+
profile.validate_override("build-override")?;
491+
profile.validate_profile(&format!("{name}.build-override"), features)?;
484492
}
485493
if let Some(ref packages) = self.package {
486494
features.require(Feature::profile_overrides())?;
487-
for profile in packages.values() {
488-
profile.validate_override("package", features)?;
495+
for (override_name, profile) in packages {
496+
profile.validate_override("package")?;
497+
profile.validate_profile(&format!("{name}.package.{override_name}"), features)?;
489498
}
490499
}
491500

@@ -548,21 +557,6 @@ impl TomlProfile {
548557
}
549558
}
550559

551-
if self.rustflags.is_some() {
552-
features.require(Feature::profile_rustflags())?;
553-
}
554-
555-
if let Some(codegen_backend) = &self.codegen_backend {
556-
features.require(Feature::codegen_backend())?;
557-
if codegen_backend.contains(|c: char| !c.is_ascii_alphanumeric() && c != '_') {
558-
bail!(
559-
"`profile.{}.codegen-backend` setting of `{}` is not a valid backend name.",
560-
name,
561-
codegen_backend,
562-
);
563-
}
564-
}
565-
566560
Ok(())
567561
}
568562

@@ -645,7 +639,28 @@ impl TomlProfile {
645639
Ok(())
646640
}
647641

648-
fn validate_override(&self, which: &str, features: &Features) -> CargoResult<()> {
642+
/// Validates a profile.
643+
///
644+
/// This is a shallow check, which is reused for the profile itself and any overrides.
645+
fn validate_profile(&self, name: &str, features: &Features) -> CargoResult<()> {
646+
if let Some(codegen_backend) = &self.codegen_backend {
647+
features.require(Feature::codegen_backend())?;
648+
if codegen_backend.contains(|c: char| !c.is_ascii_alphanumeric() && c != '_') {
649+
bail!(
650+
"`profile.{}.codegen-backend` setting of `{}` is not a valid backend name.",
651+
name,
652+
codegen_backend,
653+
);
654+
}
655+
}
656+
if self.rustflags.is_some() {
657+
features.require(Feature::profile_rustflags())?;
658+
}
659+
Ok(())
660+
}
661+
662+
/// Validation that is specific to an override.
663+
fn validate_override(&self, which: &str) -> CargoResult<()> {
649664
if self.package.is_some() {
650665
bail!("package-specific profiles cannot be nested");
651666
}
@@ -661,9 +676,6 @@ impl TomlProfile {
661676
if self.rpath.is_some() {
662677
bail!("`rpath` may not be specified in a `{}` profile", which)
663678
}
664-
if self.codegen_backend.is_some() {
665-
features.require(Feature::codegen_backend())?;
666-
}
667679
Ok(())
668680
}
669681

tests/testsuite/profiles.rs

+36
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use std::env;
44

55
use cargo_test_support::project;
6+
use cargo_test_support::registry::Package;
67

78
#[cargo_test]
89
fn profile_overrides() {
@@ -660,6 +661,41 @@ fn rustflags_requires_cargo_feature() {
660661
"\
661662
[ERROR] failed to parse manifest at `[CWD]/Cargo.toml`
662663
664+
Caused by:
665+
feature `profile-rustflags` is required
666+
667+
The package requires the Cargo feature called `profile-rustflags`, but that feature is \
668+
not stabilized in this version of Cargo (1.[..]).
669+
Consider adding `cargo-features = [\"profile-rustflags\"]` to the top of Cargo.toml \
670+
(above the [package] table) to tell Cargo you are opting in to use this unstable feature.
671+
See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#profile-rustflags-option \
672+
for more information about the status of this feature.
673+
",
674+
)
675+
.run();
676+
677+
Package::new("bar", "1.0.0").publish();
678+
p.change_file(
679+
"Cargo.toml",
680+
r#"
681+
[package]
682+
name = "foo"
683+
version = "0.0.1"
684+
685+
[dependencies]
686+
bar = "1.0"
687+
688+
[profile.dev.package.bar]
689+
rustflags = ["-C", "link-dead-code=yes"]
690+
"#,
691+
);
692+
p.cargo("check")
693+
.masquerade_as_nightly_cargo()
694+
.with_status(101)
695+
.with_stderr(
696+
"\
697+
error: failed to parse manifest at `[ROOT]/foo/Cargo.toml`
698+
663699
Caused by:
664700
feature `profile-rustflags` is required
665701

0 commit comments

Comments
 (0)