Skip to content

Commit 73dba76

Browse files
committed
Support custom profiles in legacy commands.
This makes the following changes: - Allows `cargo check`, `cargo fix`, and `cargo rustc` to support custom named profiles. This retains the legacy behavior of those commands. - Fixes `cargo bench` so that it supports custom named profiles.
1 parent 51dc5db commit 73dba76

File tree

14 files changed

+111
-98
lines changed

14 files changed

+111
-98
lines changed

src/bin/cargo/commands/bench.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ pub fn cli() -> App {
3535
"Exclude packages from the benchmark",
3636
)
3737
.arg_jobs()
38+
.arg_profile("Build artifacts with the specified profile")
3839
.arg_features()
3940
.arg_target_triple("Build for the target triple")
4041
.arg_target_dir()
@@ -55,11 +56,11 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
5556
config,
5657
CompileMode::Bench,
5758
Some(&ws),
58-
ProfileChecking::Checked,
59+
ProfileChecking::Custom,
5960
)?;
6061

6162
compile_opts.build_config.requested_profile =
62-
args.get_profile_name(config, "bench", ProfileChecking::Checked)?;
63+
args.get_profile_name(config, "bench", ProfileChecking::Custom)?;
6364

6465
let ops = TestOptions {
6566
no_run: args.is_present("no-run"),

src/bin/cargo/commands/build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
5353
config,
5454
CompileMode::Build,
5555
Some(&ws),
56-
ProfileChecking::Checked,
56+
ProfileChecking::Custom,
5757
)?;
5858

5959
if let Some(out_dir) = args.value_of_path("out-dir", config) {

src/bin/cargo/commands/check.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,11 @@ pub fn cli() -> App {
4141

4242
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
4343
let ws = args.workspace(config)?;
44-
let test = match args.value_of("profile") {
45-
Some("test") => true,
46-
None => false,
47-
Some(profile) => {
48-
let err = anyhow::format_err!(
49-
"unknown profile: `{}`, only `test` is \
50-
currently supported",
51-
profile
52-
);
53-
return Err(CliError::new(err, 101));
54-
}
55-
};
44+
// This is a legacy behavior that causes `cargo check` to pass `--test`.
45+
let test = matches!(args.value_of("profile"), Some("test"));
5646
let mode = CompileMode::Check { test };
57-
let compile_opts = args.compile_options(config, mode, Some(&ws), ProfileChecking::Unchecked)?;
47+
let compile_opts =
48+
args.compile_options(config, mode, Some(&ws), ProfileChecking::LegacyTestOnly)?;
5849

5950
ops::compile(&ws, &compile_opts)?;
6051
Ok(())

src/bin/cargo/commands/clean.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
2828
config,
2929
spec: values(args, "package"),
3030
targets: args.targets(),
31-
requested_profile: args.get_profile_name(config, "dev", ProfileChecking::Checked)?,
31+
requested_profile: args.get_profile_name(config, "dev", ProfileChecking::Custom)?,
3232
profile_specified: args.is_present("profile") || args.is_present("release"),
3333
doc: args.is_present("doc"),
3434
};

src/bin/cargo/commands/doc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
4141
deps: !args.is_present("no-deps"),
4242
};
4343
let mut compile_opts =
44-
args.compile_options(config, mode, Some(&ws), ProfileChecking::Checked)?;
44+
args.compile_options(config, mode, Some(&ws), ProfileChecking::Custom)?;
4545
compile_opts.rustdoc_document_private_items = args.is_present("document-private-items");
4646

4747
let doc_opts = DocOptions {

src/bin/cargo/commands/fix.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -67,23 +67,14 @@ pub fn cli() -> App {
6767

6868
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
6969
let ws = args.workspace(config)?;
70-
let test = match args.value_of("profile") {
71-
Some("test") => true,
72-
None => false,
73-
Some(profile) => {
74-
let err = anyhow::format_err!(
75-
"unknown profile: `{}`, only `test` is \
76-
currently supported",
77-
profile
78-
);
79-
return Err(CliError::new(err, 101));
80-
}
81-
};
70+
// This is a legacy behavior that causes `cargo fix` to pass `--test`.
71+
let test = matches!(args.value_of("profile"), Some("test"));
8272
let mode = CompileMode::Check { test };
8373

8474
// Unlike other commands default `cargo fix` to all targets to fix as much
8575
// code as we can.
86-
let mut opts = args.compile_options(config, mode, Some(&ws), ProfileChecking::Unchecked)?;
76+
let mut opts =
77+
args.compile_options(config, mode, Some(&ws), ProfileChecking::LegacyTestOnly)?;
8778

8879
if let CompileFilter::Default { .. } = opts.filter {
8980
opts.filter = CompileFilter::Only {

src/bin/cargo/commands/install.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,11 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
131131
config,
132132
CompileMode::Build,
133133
workspace.as_ref(),
134-
ProfileChecking::Checked,
134+
ProfileChecking::Custom,
135135
)?;
136136

137137
compile_opts.build_config.requested_profile =
138-
args.get_profile_name(config, "release", ProfileChecking::Checked)?;
138+
args.get_profile_name(config, "release", ProfileChecking::Custom)?;
139139

140140
if args.is_present("list") {
141141
ops::install_list(root, config)?;

src/bin/cargo/commands/run.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
3737
config,
3838
CompileMode::Build,
3939
Some(&ws),
40-
ProfileChecking::Checked,
40+
ProfileChecking::Custom,
4141
)?;
4242

4343
// Disallow `spec` to be an glob pattern

src/bin/cargo/commands/rustc.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::command_prelude::*;
2-
32
use cargo::ops;
3+
use cargo::util::interning::InternedString;
44

55
const PRINT_ARG_NAME: &str = "print";
66

@@ -46,26 +46,24 @@ pub fn cli() -> App {
4646

4747
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
4848
let ws = args.workspace(config)?;
49+
// This is a legacy behavior that changes the behavior based on the profile.
50+
// If we want to support this more formally, I think adding a --mode flag
51+
// would be warranted.
4952
let mode = match args.value_of("profile") {
50-
Some("dev") | None => CompileMode::Build,
5153
Some("test") => CompileMode::Test,
5254
Some("bench") => CompileMode::Bench,
5355
Some("check") => CompileMode::Check { test: false },
54-
Some(mode) => {
55-
let err = anyhow::format_err!(
56-
"unknown profile: `{}`, use dev,
57-
test, or bench",
58-
mode
59-
);
60-
return Err(CliError::new(err, 101));
61-
}
56+
_ => CompileMode::Build,
6257
};
6358
let mut compile_opts = args.compile_options_for_single_package(
6459
config,
6560
mode,
6661
Some(&ws),
67-
ProfileChecking::Unchecked,
62+
ProfileChecking::LegacyRustc,
6863
)?;
64+
if compile_opts.build_config.requested_profile == "check" {
65+
compile_opts.build_config.requested_profile = InternedString::new("dev");
66+
}
6967
let target_args = values(args, "args");
7068
compile_opts.target_rustc_args = if target_args.is_empty() {
7169
None

src/bin/cargo/commands/rustdoc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
4444
config,
4545
CompileMode::Doc { deps: false },
4646
Some(&ws),
47-
ProfileChecking::Checked,
47+
ProfileChecking::Custom,
4848
)?;
4949
let target_args = values(args, "args");
5050
compile_opts.target_rustdoc_args = if target_args.is_empty() {

src/bin/cargo/commands/test.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,11 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
6666
config,
6767
CompileMode::Test,
6868
Some(&ws),
69-
ProfileChecking::Checked,
69+
ProfileChecking::Custom,
7070
)?;
7171

7272
compile_opts.build_config.requested_profile =
73-
args.get_profile_name(config, "test", ProfileChecking::Checked)?;
73+
args.get_profile_name(config, "test", ProfileChecking::Custom)?;
7474

7575
// `TESTNAME` is actually an argument of the test binary, but it's
7676
// important, so we explicitly mention it and reconfigure.

src/cargo/core/profiles.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ impl Profiles {
133133
fn predefined_dir_names() -> HashMap<InternedString, InternedString> {
134134
let mut dir_names = HashMap::new();
135135
dir_names.insert(InternedString::new("dev"), InternedString::new("debug"));
136-
dir_names.insert(InternedString::new("check"), InternedString::new("debug"));
137136
dir_names.insert(InternedString::new("test"), InternedString::new("debug"));
138137
dir_names.insert(InternedString::new("bench"), InternedString::new("release"));
139138
dir_names
@@ -174,13 +173,6 @@ impl Profiles {
174173
..TomlProfile::default()
175174
},
176175
),
177-
(
178-
"check",
179-
TomlProfile {
180-
inherits: Some(InternedString::new("dev")),
181-
..TomlProfile::default()
182-
},
183-
),
184176
(
185177
"doc",
186178
TomlProfile {

src/cargo/util/command_prelude.rs

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,14 @@ pub fn subcommand(name: &'static str) -> App {
281281

282282
// Determines whether or not to gate `--profile` as unstable when resolving it.
283283
pub enum ProfileChecking {
284-
Checked,
285-
Unchecked,
284+
// `cargo rustc` historically has allowed "test", "bench", and "check". This
285+
// variant explicitly allows those.
286+
LegacyRustc,
287+
// `cargo check` and `cargo fix` historically has allowed "test". This variant
288+
// explicitly allows that on stable.
289+
LegacyTestOnly,
290+
// All other commands, which allow any valid custom named profile.
291+
Custom,
286292
}
287293

288294
pub trait ArgMatchesExt {
@@ -345,13 +351,18 @@ pub trait ArgMatchesExt {
345351
) -> CargoResult<InternedString> {
346352
let specified_profile = self._value_of("profile");
347353

348-
match profile_checking {
349-
ProfileChecking::Unchecked => {}
350-
ProfileChecking::Checked => {
351-
if specified_profile.is_some() && !config.cli_unstable().unstable_options {
352-
anyhow::bail!("Usage of `--profile` requires `-Z unstable-options`")
353-
}
354-
}
354+
// Check for allowed legacy names.
355+
// This is an early exit, since it allows combination with `--release`.
356+
match (specified_profile, profile_checking) {
357+
// `cargo rustc` has legacy handling of these names
358+
(Some(name @ ("test" | "bench" | "check")), ProfileChecking::LegacyRustc) |
359+
// `cargo fix` and `cargo check` has legacy handling of this profile name
360+
(Some(name @ "test"), ProfileChecking::LegacyTestOnly) => return Ok(InternedString::new(name)),
361+
_ => {}
362+
}
363+
364+
if specified_profile.is_some() && !config.cli_unstable().unstable_options {
365+
bail!("usage of `--profile` requires `-Z unstable-options`");
355366
}
356367

357368
let conflict = |flag: &str, equiv: &str, specified: &str| -> anyhow::Error {
@@ -371,35 +382,15 @@ pub trait ArgMatchesExt {
371382
specified_profile,
372383
) {
373384
(false, false, None) => default,
374-
// `check` is separate from all other reservations because
375-
// `--profile=check` has been stable for the `cargo rustc` command
376-
// for a long time. The Unchecked commands (check, fix, rustc)
377-
// have their own validation.
378-
//
379-
// This is explicitly ordered before the --release conflict check
380-
// since `cargo rustc --profile=check --release` means to check in
381-
// release mode.
382-
//
383-
// When stabilizing, only `cargo rustc` should be allowed to use
384-
// `check` with the old semantics.
385-
(_, _, Some(name @ ("test" | "bench" | "check"))) => match profile_checking {
386-
ProfileChecking::Unchecked => name,
387-
ProfileChecking::Checked => {
388-
bail!(
389-
"profile `{}` is reserved and not allowed to be explicitly specified",
390-
name
391-
)
392-
}
393-
},
394385
(true, _, None | Some("release")) => "release",
395386
(true, _, Some(name)) => return Err(conflict("release", "release", name)),
396387
(_, true, None | Some("dev")) => "dev",
397388
(_, true, Some(name)) => return Err(conflict("debug", "dev", name)),
398389
// `doc` is separate from all the other reservations because
399390
// [profile.doc] was historically allowed, but is deprecated and
400391
// has no effect. To avoid potentially breaking projects, it is a
401-
// warning, but since `--profile` is new, we can reject it
402-
// completely here.
392+
// warning in Cargo.toml, but since `--profile` is new, we can
393+
// reject it completely here.
403394
(_, _, Some("doc")) => {
404395
bail!("profile `doc` is reserved and not allowed to be explicitly specified")
405396
}

tests/testsuite/profile_custom.rs

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,25 @@
11
//! Tests for named profiles.
22
3+
use cargo_test_support::paths::CargoPathExt;
34
use cargo_test_support::{basic_lib_manifest, project};
45

6+
#[cargo_test]
7+
fn gated() {
8+
let p = project().file("src/lib.rs", "").build();
9+
// `rustc`, `fix`, and `check` have had `--profile` before custom named profiles.
10+
// Without unstable, these shouldn't be allowed to access non-legacy names.
11+
for command in [
12+
"rustc", "fix", "check", "bench", "clean", "install", "test", "build", "doc", "run",
13+
"rustdoc",
14+
] {
15+
p.cargo(command)
16+
.arg("--profile=release")
17+
.with_status(101)
18+
.with_stderr("error: usage of `--profile` requires `-Z unstable-options`")
19+
.run();
20+
}
21+
}
22+
523
#[cargo_test]
624
fn inherits_on_release() {
725
let p = project()
@@ -562,18 +580,13 @@ fn reserved_profile_names() {
562580
.file("src/lib.rs", "")
563581
.build();
564582

565-
for name in ["check", "doc"] {
566-
p.cargo(&format!("build --profile={} -Zunstable-options", name))
567-
.masquerade_as_nightly_cargo()
568-
.with_status(101)
569-
.with_stderr(&format!(
570-
"error: profile `{}` is reserved and not allowed to be explicitly specified",
571-
name
572-
))
573-
.run();
574-
}
583+
p.cargo("build --profile=doc -Zunstable-options")
584+
.masquerade_as_nightly_cargo()
585+
.with_status(101)
586+
.with_stderr("error: profile `doc` is reserved and not allowed to be explicitly specified")
587+
.run();
575588
// Not an exhaustive list, just a sample.
576-
for name in ["build", "cargo", "rustc", "CaRgO_startswith"] {
589+
for name in ["build", "cargo", "check", "rustc", "CaRgO_startswith"] {
577590
p.cargo(&format!("build --profile={} -Zunstable-options", name))
578591
.masquerade_as_nightly_cargo()
579592
.with_status(101)
@@ -653,3 +666,39 @@ Caused by:
653666
)
654667
.run();
655668
}
669+
670+
#[cargo_test]
671+
fn legacy_commands_support_custom() {
672+
// These commands have had `--profile` before custom named profiles.
673+
let p = project()
674+
.file(
675+
"Cargo.toml",
676+
r#"
677+
cargo-features = ["named-profiles"]
678+
679+
[package]
680+
name = "foo"
681+
version = "0.1.0"
682+
683+
[profile.super-dev]
684+
codegen-units = 3
685+
inherits = "dev"
686+
"#,
687+
)
688+
.file("src/lib.rs", "")
689+
.build();
690+
691+
for command in ["rustc", "fix", "check"] {
692+
let mut pb = p.cargo(command);
693+
if command == "fix" {
694+
pb.arg("--allow-no-vcs");
695+
}
696+
pb.arg("--profile=super-dev")
697+
.arg("-Zunstable-options")
698+
.arg("-v")
699+
.masquerade_as_nightly_cargo()
700+
.with_stderr_contains("[RUNNING] [..]codegen-units=3[..]")
701+
.run();
702+
p.build_dir().rm_rf();
703+
}
704+
}

0 commit comments

Comments
 (0)