use std::path::PathBuf;
use std::process::Command;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::heading;
use clap::{ArgAction, Parser};
#[derive(Clone, Debug, Default, Parser)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct CommonOptions {
#[arg(short = 'q', long)]
#[cfg_attr(feature = "serde", serde(default))]
pub quiet: bool,
#[arg(
short = 'j',
long,
value_name = "N",
allow_hyphen_values = true,
help_heading = heading::COMPILATION_OPTIONS,
)]
#[cfg_attr(feature = "serde", serde(default))]
pub jobs: Option<usize>,
#[arg(long, help_heading = heading::COMPILATION_OPTIONS)]
#[cfg_attr(feature = "serde", serde(default))]
pub keep_going: bool,
#[arg(
long,
value_name = "PROFILE-NAME",
help_heading = heading::COMPILATION_OPTIONS,
)]
#[cfg_attr(feature = "serde", serde(default))]
pub profile: Option<String>,
#[arg(
short = 'F',
long,
action = ArgAction::Append,
help_heading = heading::FEATURE_SELECTION,
)]
#[cfg_attr(feature = "serde", serde(default))]
pub features: Vec<String>,
#[arg(long, help_heading = heading::FEATURE_SELECTION)]
#[cfg_attr(feature = "serde", serde(default))]
pub all_features: bool,
#[arg(long, help_heading = heading::FEATURE_SELECTION)]
#[cfg_attr(feature = "serde", serde(default))]
pub no_default_features: bool,
#[arg(
long,
value_name = "TRIPLE",
num_args = 0..=1,
default_missing_value = "",
action = ArgAction::Append,
help_heading = heading::COMPILATION_OPTIONS,
)]
#[cfg_attr(feature = "serde", serde(default))]
pub target: Vec<String>,
#[arg(
long,
value_name = "DIRECTORY",
help_heading = heading::COMPILATION_OPTIONS,
)]
#[cfg_attr(feature = "serde", serde(default))]
pub target_dir: Option<PathBuf>,
#[arg(
long,
value_name = "FMT",
action = ArgAction::Append,
value_delimiter = ',',
ignore_case = true,
value_parser = [
"human",
"short",
"json",
"json-diagnostic-short",
"json-diagnostic-rendered-ansi",
"json-render-diagnostics",
],
)]
#[cfg_attr(feature = "serde", serde(default))]
pub message_format: Vec<String>,
#[arg(short = 'v', long, action = ArgAction::Count)]
#[cfg_attr(feature = "serde", serde(default))]
pub verbose: u8,
#[arg(long, value_name = "WHEN", value_parser = ["auto", "always", "never"])]
#[cfg_attr(feature = "serde", serde(default))]
pub color: Option<String>,
#[arg(long, help_heading = heading::MANIFEST_OPTIONS)]
#[cfg_attr(feature = "serde", serde(default))]
pub frozen: bool,
#[arg(long, help_heading = heading::MANIFEST_OPTIONS)]
#[cfg_attr(feature = "serde", serde(default))]
pub locked: bool,
#[arg(long, help_heading = heading::MANIFEST_OPTIONS)]
#[cfg_attr(feature = "serde", serde(default))]
pub offline: bool,
#[arg(long, value_name = "KEY=VALUE|PATH", action = ArgAction::Append)]
#[cfg_attr(feature = "serde", serde(default))]
pub config: Vec<String>,
#[arg(short = 'Z', value_name = "FLAG", action = ArgAction::Append)]
#[cfg_attr(feature = "serde", serde(default))]
pub unstable_flags: Vec<String>,
#[arg(long, help_heading = heading::COMPILATION_OPTIONS)]
#[cfg_attr(feature = "serde", serde(default))]
pub timings: bool,
}
impl CommonOptions {
pub fn apply(&self, cmd: &mut Command) {
if self.quiet {
cmd.arg("--quiet");
}
if let Some(jobs) = self.jobs {
cmd.arg("--jobs").arg(jobs.to_string());
}
if self.keep_going {
cmd.arg("--keep-going");
}
if let Some(profile) = self.profile.as_ref() {
cmd.arg("--profile").arg(profile);
}
for feature in &self.features {
cmd.arg("--features").arg(feature);
}
if self.all_features {
cmd.arg("--all-features");
}
if self.no_default_features {
cmd.arg("--no-default-features");
}
let rust_targets = self
.target
.iter()
.map(|target| target.split_once('.').map(|(t, _)| t).unwrap_or(target))
.collect::<Vec<&str>>();
rust_targets.iter().for_each(|target| {
cmd.arg("--target");
if !target.is_empty() {
cmd.arg(target);
}
});
if let Some(dir) = self.target_dir.as_ref() {
cmd.arg("--target-dir").arg(dir);
}
for fmt in &self.message_format {
cmd.arg("--message-format").arg(fmt);
}
if self.verbose > 0 {
cmd.arg(format!("-{}", "v".repeat(self.verbose.into())));
}
if let Some(color) = self.color.as_ref() {
cmd.arg("--color").arg(color);
}
if self.frozen {
cmd.arg("--frozen");
}
if self.locked {
cmd.arg("--locked");
}
if self.offline {
cmd.arg("--offline");
}
for config in &self.config {
cmd.arg("--config").arg(config);
}
for flag in &self.unstable_flags {
cmd.arg("-Z").arg(flag);
}
if self.timings {
cmd.arg("--timings");
}
}
pub(crate) fn cargo_command() -> Command {
let cargo = match std::env::var_os("CARGO") {
Some(cargo) => cargo.into(),
None => PathBuf::from("cargo"),
};
let mut cmd = Command::new(cargo);
cmd.env_remove("CARGO");
cmd
}
}