Skip to content

Commit

Permalink
Merge #921
Browse files Browse the repository at this point in the history
921: Support cargo term variables. r=Emilgardis a=Alexhuszagh

Use the `CARGO_TERM_VERBOSE`, `CARGO_TERM_QUIET`, and `CARGO_TERM_COLOR` environment variables for cross terminal output. This enables us to detect term settings via environment variables, which are overridden by command-line flags, which is our own behavior.

Cargo has CLI flags override environment variables, and verbose and quiet cannot be set for the same level. So if `CARGO_TERM_VERBOSE=true` and `--quiet` are used, then we use the quiet setting, but if `--verbose` and `--quiet` are used, then we print a fatal error message.

Closes #919.

Co-authored-by: Alex Huszagh <ahuszagh@gmail.com>
  • Loading branch information
bors[bot] and Alexhuszagh authored Jul 8, 2022
2 parents ddccccd + 1b47477 commit f6e67ce
Show file tree
Hide file tree
Showing 11 changed files with 135 additions and 42 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Added

- #921 - use `CARGO_TERM_VERBOSE`, `CARGO_TERM_QUIET`, and `CARGO_TERM_COLOR` environment variables for cross terminal output.
- #913 - added the `x86_64-unknown-illumos` target.
- #910 - `pre-build` can now take a string pointing to a script file to run.
- #905 - added `qemu-runner` for musl images, allowing use of native or emulated runners.
Expand Down
2 changes: 1 addition & 1 deletion src/bin/commands/clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub struct Clean {
/// Do not print cross log messages.
#[clap(short, long)]
pub quiet: bool,
/// Whether messages should use color output.
/// Coloring: auto, always, never
#[clap(long)]
pub color: Option<String>,
/// Force removal of images.
Expand Down
14 changes: 7 additions & 7 deletions src/bin/commands/containers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub struct ListVolumes {
/// Do not print cross log messages.
#[clap(short, long)]
pub quiet: bool,
/// Whether messages should use color output.
/// Coloring: auto, always, never
#[clap(long)]
pub color: Option<String>,
/// Container engine (such as docker or podman).
Expand All @@ -34,7 +34,7 @@ pub struct RemoveAllVolumes {
/// Do not print cross log messages.
#[clap(short, long)]
pub quiet: bool,
/// Whether messages should use color output.
/// Coloring: auto, always, never
#[clap(long)]
pub color: Option<String>,
/// Force removal of volumes.
Expand Down Expand Up @@ -62,7 +62,7 @@ pub struct PruneVolumes {
/// Do not print cross log messages.
#[clap(short, long)]
pub quiet: bool,
/// Whether messages should use color output.
/// Coloring: auto, always, never
#[clap(long)]
pub color: Option<String>,
/// Remove volumes. Default is a dry run.
Expand Down Expand Up @@ -93,7 +93,7 @@ pub struct CreateVolume {
/// Do not print cross log messages.
#[clap(short, long)]
pub quiet: bool,
/// Whether messages should use color output.
/// Coloring: auto, always, never
#[clap(long)]
pub color: Option<String>,
/// Container engine (such as docker or podman).
Expand Down Expand Up @@ -126,7 +126,7 @@ pub struct RemoveVolume {
/// Do not print cross log messages.
#[clap(short, long)]
pub quiet: bool,
/// Whether messages should use color output.
/// Coloring: auto, always, never
#[clap(long)]
pub color: Option<String>,
/// Container engine (such as docker or podman).
Expand Down Expand Up @@ -223,7 +223,7 @@ pub struct ListContainers {
/// Do not print cross log messages.
#[clap(short, long)]
pub quiet: bool,
/// Whether messages should use color output.
/// Coloring: auto, always, never
#[clap(long)]
pub color: Option<String>,
/// Container engine (such as docker or podman).
Expand All @@ -245,7 +245,7 @@ pub struct RemoveAllContainers {
/// Do not print cross log messages.
#[clap(short, long)]
pub quiet: bool,
/// Whether messages should use color output.
/// Coloring: auto, always, never
#[clap(long)]
pub color: Option<String>,
/// Force removal of containers.
Expand Down
4 changes: 2 additions & 2 deletions src/bin/commands/images.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub struct ListImages {
/// Do not print cross log messages.
#[clap(short, long)]
pub quiet: bool,
/// Whether messages should use color output.
/// Coloring: auto, always, never
#[clap(long)]
pub color: Option<String>,
/// Container engine (such as docker or podman).
Expand All @@ -46,7 +46,7 @@ pub struct RemoveImages {
/// Do not print cross log messages.
#[clap(short, long)]
pub quiet: bool,
/// Whether messages should use color output.
/// Coloring: auto, always, never
#[clap(long)]
pub color: Option<String>,
/// Force removal of images.
Expand Down
5 changes: 2 additions & 3 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{env, path::PathBuf};
use crate::cargo::Subcommand;
use crate::errors::Result;
use crate::rustc::TargetList;
use crate::shell::MessageInfo;
use crate::shell::{self, MessageInfo};
use crate::Target;

#[derive(Debug)]
Expand Down Expand Up @@ -143,7 +143,6 @@ pub fn parse(target_list: &TargetList) -> Result<Args> {
let mut quiet = false;
let mut verbose = false;
let mut color = None;
let mut default_msg_info = MessageInfo::default();

{
let mut args = env::args().skip(1);
Expand All @@ -164,7 +163,7 @@ pub fn parse(target_list: &TargetList) -> Result<Args> {
ArgKind::Next => {
match parse_next_arg(arg, &mut all, ToOwned::to_owned, &mut args) {
Some(c) => Some(c),
None => default_msg_info.fatal_usage("--color <WHEN>", 1),
None => shell::invalid_color(None),
}
}
ArgKind::Equal => Some(parse_equal_arg(arg, &mut all, ToOwned::to_owned)),
Expand Down
135 changes: 112 additions & 23 deletions src/shell.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// This file was adapted from:
// https://github.com/rust-lang/cargo/blob/ca4edabb28fc96fdf2a1d56fe3851831ac166f8a/src/cargo/core/shell.rs

use std::env;
use std::fmt;
use std::io::{self, Write};
use std::str::FromStr;

use crate::errors::Result;
use owo_colors::{self, OwoColorize};
Expand Down Expand Up @@ -77,6 +79,23 @@ impl Verbosity {
Self::Normal | Self::Quiet => false,
}
}

fn create(color_choice: ColorChoice, verbose: bool, quiet: bool) -> Option<Self> {
match (verbose, quiet) {
(true, true) => {
MessageInfo::from(color_choice).fatal("cannot set both --verbose and --quiet", 101)
}
(true, false) => Some(Verbosity::Verbose),
(false, true) => Some(Verbosity::Quiet),
(false, false) => None,
}
}
}

impl Default for Verbosity {
fn default() -> Verbosity {
Verbosity::Normal
}
}

/// Whether messages should use color output
Expand All @@ -90,6 +109,21 @@ pub enum ColorChoice {
Auto,
}

impl FromStr for ColorChoice {
type Err = eyre::ErrReport;

fn from_str(s: &str) -> Result<ColorChoice> {
match s {
"always" => Ok(ColorChoice::Always),
"never" => Ok(ColorChoice::Never),
"auto" => Ok(ColorChoice::Auto),
arg => eyre::bail!(
"argument for --color must be auto, always, or never, but found `{arg}`"
),
}
}
}

// Should simplify the APIs a lot.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MessageInfo {
Expand Down Expand Up @@ -241,19 +275,62 @@ impl MessageInfo {
}
}

pub fn fatal_usage<T: fmt::Display>(&mut self, arg: T, code: i32) -> ! {
self.error_usage(arg)
pub fn fatal_usage<T: fmt::Display>(
&mut self,
arg: T,
provided: Option<&str>,
possible: Option<&[&str]>,
code: i32,
) -> ! {
self.error_usage(arg, provided, possible)
.expect("could not display usage message");
std::process::exit(code);
}

fn error_usage<T: fmt::Display>(&mut self, arg: T) -> Result<()> {
fn error_usage<T: fmt::Display>(
&mut self,
arg: T,
provided: Option<&str>,
possible: Option<&[&str]>,
) -> Result<()> {
let mut stream = io::stderr();
write_style!(stream, self, cross_prefix!("error"), bold, red);
write_style!(stream, self, ":", bold);
write_style!(stream, self, " The argument '");
write_style!(stream, self, arg, yellow);
write_style!(stream, self, "' requires a value but none was supplied\n");
match provided {
Some(value) => {
write_style!(
stream,
self,
format_args!(" \"{value}\" isn't a valid value for '")
);
write_style!(stream, self, arg, yellow);
write_style!(stream, self, "'\n");
}
None => {
write_style!(stream, self, " The argument '");
write_style!(stream, self, arg, yellow);
write_style!(stream, self, "' requires a value but none was supplied\n");
}
}
match possible {
Some(values) if !values.is_empty() => {
let error_indent = cross_prefix!("error: ").len();
write_style!(
stream,
self,
format_args!("{:error_indent$}[possible values: ", "")
);
let max_index = values.len() - 1;
for (index, value) in values.iter().enumerate() {
write_style!(stream, self, value, green);
if index < max_index {
write_style!(stream, self, ", ");
}
}
write_style!(stream, self, "]\n");
}
_ => (),
}
write_style!(stream, self, "Usage:\n");
write_style!(
stream,
Expand Down Expand Up @@ -295,27 +372,39 @@ impl From<(ColorChoice, Verbosity)> for MessageInfo {
}
}

fn get_color_choice(color: Option<&str>) -> Result<ColorChoice> {
match color {
Some("always") => Ok(ColorChoice::Always),
Some("never") => Ok(ColorChoice::Never),
Some("auto") | None => Ok(ColorChoice::Auto),
Some(arg) => {
eyre::bail!("argument for --color must be auto, always, or never, but found `{arg}`")
}
// cargo only accepts literal booleans for some values.
pub fn cargo_envvar_bool(var: &str) -> Result<bool> {
match env::var(var).ok() {
Some(value) => value.parse::<bool>().map_err(|_ignore| {
eyre::eyre!("environment variable for `{var}` was not `true` or `false`.")
}),
None => Ok(false),
}
}

pub fn invalid_color(provided: Option<&str>) -> ! {
let possible = ["auto", "always", "never"];
MessageInfo::default().fatal_usage("--color <WHEN>", provided, Some(&possible), 1);
}

fn get_color_choice(color: Option<&str>) -> Result<ColorChoice> {
Ok(match color {
Some(arg) => arg.parse().unwrap_or_else(|_| invalid_color(color)),
None => match env::var("CARGO_TERM_COLOR").ok().as_deref() {
Some(arg) => arg.parse().unwrap_or_else(|_| invalid_color(color)),
None => ColorChoice::Auto,
},
})
}

fn get_verbosity(color_choice: ColorChoice, verbose: bool, quiet: bool) -> Result<Verbosity> {
match (verbose, quiet) {
(true, true) => {
MessageInfo::from(color_choice).error("cannot set both --verbose and --quiet")?;
std::process::exit(101);
}
(true, false) => Ok(Verbosity::Verbose),
(false, true) => Ok(Verbosity::Quiet),
(false, false) => Ok(Verbosity::Normal),
}
// cargo always checks the value of these variables.
let env_verbose = cargo_envvar_bool("CARGO_TERM_VERBOSE")?;
let env_quiet = cargo_envvar_bool("CARGO_TERM_QUIET")?;
Ok(match Verbosity::create(color_choice, verbose, quiet) {
Some(v) => v,
None => Verbosity::create(color_choice, env_verbose, env_quiet).unwrap_or_default(),
})
}

pub trait Stream {
Expand Down
6 changes: 5 additions & 1 deletion xtask/src/build_docker_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub struct BuildDockerImage {
/// Do not print cross log messages.
#[clap(short, long)]
pub quiet: bool,
/// Whether messages should use color output.
/// Coloring: auto, always, never
#[clap(long)]
pub color: Option<String>,
/// Print but do not execute the build commands.
Expand Down Expand Up @@ -112,6 +112,10 @@ pub fn build_docker_image(
engine: &docker::Engine,
msg_info: &mut MessageInfo,
) -> cross::Result<()> {
let verbose = match verbose {
0 => msg_info.is_verbose() as u8,
v => v,
};
let metadata = cargo_metadata(msg_info)?;
let version = metadata
.get_package("cross")
Expand Down
2 changes: 1 addition & 1 deletion xtask/src/crosstool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub struct ConfigureCrosstool {
/// Do not print cross log messages.
#[clap(short, long)]
pub quiet: bool,
/// Whether messages should use color output.
/// Coloring: auto, always, never
#[clap(long)]
pub color: Option<String>,
/// The gcc version to configure for.
Expand Down
4 changes: 2 additions & 2 deletions xtask/src/hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub struct Check {
/// Do not print cross log messages.
#[clap(short, long)]
pub quiet: bool,
/// Whether messages should use color output.
/// Coloring: auto, always, never
#[clap(long)]
pub color: Option<String>,
/// Run shellcheck on all files, not just staged files.
Expand All @@ -34,7 +34,7 @@ pub struct Test {
/// Do not print cross log messages.
#[clap(short, long)]
pub quiet: bool,
/// Whether messages should use color output.
/// Coloring: auto, always, never
#[clap(long)]
pub color: Option<String>,
}
Expand Down
2 changes: 1 addition & 1 deletion xtask/src/install_git_hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub struct InstallGitHooks {
/// Do not print cross log messages.
#[clap(short, long)]
pub quiet: bool,
/// Whether messages should use color output.
/// Coloring: auto, always, never
#[clap(long)]
pub color: Option<String>,
}
Expand Down
2 changes: 1 addition & 1 deletion xtask/src/target_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub struct TargetInfo {
/// Do not print cross log messages.
#[clap(short, long)]
pub quiet: bool,
/// Whether messages should use color output.
/// Coloring: auto, always, never
#[clap(long)]
pub color: Option<String>,
/// Image registry.
Expand Down

0 comments on commit f6e67ce

Please sign in to comment.