Skip to content

Commit 03bc66b

Browse files
committed
Auto merge of #12305 - epage:quiet, r=weihanglo
fix(script): Be quiet on programmatic output ### What does this PR try to resolve? This is a part of #12207 The goal is that we shouldn't interfere with end-user output when "cargo script"s are used programmatically. The only way to detect this is when piping. CI will also look like this. My thought is that if someone does want to do `#!/usr/bin/env -S cargo -v`, it should have a consistent meaning between local development (`cargo run --manifest-path`) and "script mode" (`cargo`), so I effectively added a new verbosity level in these cases. To get normal output in all cases, add a `-v` like the tests do. Do `-vv` if you want the normal `-v` mode. If you want it always quiet, do `--quiet`. I want to see the default verbosity for interactive "script mode" a bit quieter to the point that all normal output cargo makes is cleared before running the built binary. I am holding off on that now as that could tie into bigger conversations / refactors (see https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo/topic/Re-thinking.20cargo's.20output). ### How should we test and review this PR? Initial writing of tests and refactors are split split out. The tests in the final commit will let you see what impact this had on behavior.
2 parents e95e2a9 + 0e648c3 commit 03bc66b

File tree

4 files changed

+144
-73
lines changed

4 files changed

+144
-73
lines changed

src/bin/cargo/cli.rs

Lines changed: 72 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use anyhow::{anyhow, Context as _};
22
use cargo::core::shell::Shell;
33
use cargo::core::{features, CliUnstable};
4-
use cargo::{self, drop_print, drop_println, CliResult, Config};
4+
use cargo::{self, drop_print, drop_println, CargoResult, CliResult, Config};
55
use clap::{Arg, ArgMatches};
66
use itertools::Itertools;
77
use std::collections::HashMap;
@@ -175,10 +175,11 @@ Run with 'cargo -Z [FLAG] [COMMAND]'",
175175
return Ok(());
176176
}
177177
};
178-
config_configure(config, &expanded_args, subcommand_args, global_args)?;
178+
let exec = Exec::infer(cmd)?;
179+
config_configure(config, &expanded_args, subcommand_args, global_args, &exec)?;
179180
super::init_git(config);
180181

181-
execute_subcommand(config, cmd, subcommand_args)
182+
exec.exec(config, subcommand_args)
182183
}
183184

184185
pub fn get_version_string(is_verbose: bool) -> String {
@@ -363,12 +364,26 @@ fn config_configure(
363364
args: &ArgMatches,
364365
subcommand_args: &ArgMatches,
365366
global_args: GlobalArgs,
367+
exec: &Exec,
366368
) -> CliResult {
367369
let arg_target_dir = &subcommand_args.value_of_path("target-dir", config);
368-
let verbose = global_args.verbose + args.verbose();
370+
let mut verbose = global_args.verbose + args.verbose();
369371
// quiet is unusual because it is redefined in some subcommands in order
370372
// to provide custom help text.
371-
let quiet = args.flag("quiet") || subcommand_args.flag("quiet") || global_args.quiet;
373+
let mut quiet = args.flag("quiet") || subcommand_args.flag("quiet") || global_args.quiet;
374+
if matches!(exec, Exec::Manifest(_)) && !quiet {
375+
// Verbosity is shifted quieter for `Exec::Manifest` as it is can be used as if you ran
376+
// `cargo install` and we especially shouldn't pollute programmatic output.
377+
//
378+
// For now, interactive output has the same default output as `cargo run` but that is
379+
// subject to change.
380+
if let Some(lower) = verbose.checked_sub(1) {
381+
verbose = lower;
382+
} else if !config.shell().is_err_tty() {
383+
// Don't pollute potentially-scripted output
384+
quiet = true;
385+
}
386+
}
372387
let global_color = global_args.color; // Extract so it can take reference.
373388
let color = args
374389
.get_one::<String>("color")
@@ -399,53 +414,64 @@ fn config_configure(
399414
Ok(())
400415
}
401416

402-
/// Precedence isn't the most obvious from this function because
403-
/// - Some is determined by `expand_aliases`
404-
/// - Some is enforced by `avoid_ambiguity_between_builtins_and_manifest_commands`
405-
///
406-
/// In actuality, it is:
407-
/// 1. built-ins xor manifest-command
408-
/// 2. aliases
409-
/// 3. external subcommands
410-
fn execute_subcommand(config: &mut Config, cmd: &str, subcommand_args: &ArgMatches) -> CliResult {
411-
if let Some(exec) = commands::builtin_exec(cmd) {
412-
return exec(config, subcommand_args);
417+
enum Exec {
418+
Builtin(commands::Exec),
419+
Manifest(String),
420+
External(String),
421+
}
422+
423+
impl Exec {
424+
/// Precedence isn't the most obvious from this function because
425+
/// - Some is determined by `expand_aliases`
426+
/// - Some is enforced by `avoid_ambiguity_between_builtins_and_manifest_commands`
427+
///
428+
/// In actuality, it is:
429+
/// 1. built-ins xor manifest-command
430+
/// 2. aliases
431+
/// 3. external subcommands
432+
fn infer(cmd: &str) -> CargoResult<Self> {
433+
if let Some(exec) = commands::builtin_exec(cmd) {
434+
Ok(Self::Builtin(exec))
435+
} else if commands::run::is_manifest_command(cmd) {
436+
Ok(Self::Manifest(cmd.to_owned()))
437+
} else {
438+
Ok(Self::External(cmd.to_owned()))
439+
}
413440
}
414441

415-
if commands::run::is_manifest_command(cmd) {
416-
let ext_path = super::find_external_subcommand(config, cmd);
417-
if !config.cli_unstable().script && ext_path.is_some() {
418-
config.shell().warn(format_args!(
419-
"\
442+
fn exec(self, config: &mut Config, subcommand_args: &ArgMatches) -> CliResult {
443+
match self {
444+
Self::Builtin(exec) => exec(config, subcommand_args),
445+
Self::Manifest(cmd) => {
446+
let ext_path = super::find_external_subcommand(config, &cmd);
447+
if !config.cli_unstable().script && ext_path.is_some() {
448+
config.shell().warn(format_args!(
449+
"\
420450
external subcommand `{cmd}` has the appearance of a manfiest-command
421451
This was previously accepted but will be phased out when `-Zscript` is stabilized.
422452
For more information, see issue #12207 <https://github.com/rust-lang/cargo/issues/12207>.",
423-
))?;
424-
let mut ext_args = vec![OsStr::new(cmd)];
425-
ext_args.extend(
426-
subcommand_args
427-
.get_many::<OsString>("")
428-
.unwrap_or_default()
429-
.map(OsString::as_os_str),
430-
);
431-
super::execute_external_subcommand(config, cmd, &ext_args)
432-
} else {
433-
let ext_args: Vec<OsString> = subcommand_args
434-
.get_many::<OsString>("")
435-
.unwrap_or_default()
436-
.cloned()
437-
.collect();
438-
commands::run::exec_manifest_command(config, cmd, &ext_args)
453+
))?;
454+
Self::External(cmd).exec(config, subcommand_args)
455+
} else {
456+
let ext_args: Vec<OsString> = subcommand_args
457+
.get_many::<OsString>("")
458+
.unwrap_or_default()
459+
.cloned()
460+
.collect();
461+
commands::run::exec_manifest_command(config, &cmd, &ext_args)
462+
}
463+
}
464+
Self::External(cmd) => {
465+
let mut ext_args = vec![OsStr::new(&cmd)];
466+
ext_args.extend(
467+
subcommand_args
468+
.get_many::<OsString>("")
469+
.unwrap_or_default()
470+
.map(OsString::as_os_str),
471+
);
472+
super::execute_external_subcommand(config, &cmd, &ext_args)
473+
}
439474
}
440-
} else {
441-
let mut ext_args = vec![OsStr::new(cmd)];
442-
ext_args.extend(
443-
subcommand_args
444-
.get_many::<OsString>("")
445-
.unwrap_or_default()
446-
.map(OsString::as_os_str),
447-
);
448-
super::execute_external_subcommand(config, cmd, &ext_args)
449475
}
450476
}
451477

src/bin/cargo/commands/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ pub fn builtin() -> Vec<Command> {
4343
]
4444
}
4545

46-
pub fn builtin_exec(cmd: &str) -> Option<fn(&mut Config, &ArgMatches) -> CliResult> {
46+
pub type Exec = fn(&mut Config, &ArgMatches) -> CliResult;
47+
48+
pub fn builtin_exec(cmd: &str) -> Option<Exec> {
4749
let f = match cmd {
4850
"add" => add::exec,
4951
"bench" => bench::exec,

src/doc/src/reference/unstable.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,6 +1484,7 @@ A parameter is identified as a manifest-command if it has one of:
14841484

14851485
Differences between `cargo run --manifest-path <path>` and `cargo <path>`
14861486
- `cargo <path>` runs with the config for `<path>` and not the current dir, more like `cargo install --path <path>`
1487+
- `cargo <path>` is at a verbosity level below the normal default. Pass `-v` to get normal output.
14871488

14881489
### `[lints]`
14891490

0 commit comments

Comments
 (0)