use std::ffi::OsString;
use std::path::PathBuf;
use clap::Parser;
use crate::compress::Format;
#[derive(Debug, Parser)]
#[command(name = "cargo", bin_name = "cargo")]
enum Cargo {
Tarball(TarballArgs),
}
#[derive(Debug, Parser)]
#[command(
version,
about = "Build compressed release archives from a Cargo project",
long_about = None,
)]
pub struct TarballArgs {
#[arg(short, long, value_name = "SPEC")]
pub package: Option<String>,
#[arg(long, value_name = "PATH")]
pub manifest_path: Option<PathBuf>,
#[arg(long, value_name = "TRIPLE")]
pub target: Option<String>,
#[arg(long, value_name = "DIR")]
pub target_dir: Option<PathBuf>,
#[arg(long, value_name = "NAME", default_value = "release")]
pub profile: String,
#[arg(short = 'F', long, value_name = "FEATURES")]
pub features: Vec<String>,
#[arg(long)]
pub no_default_features: bool,
#[arg(long, conflicts_with = "no_default_features")]
pub all_features: bool,
#[arg(long, value_name = "NAME")]
pub bin: Vec<String>,
#[arg(long)]
pub no_build: bool,
#[arg(short, long, value_name = "PATH")]
pub output: Option<PathBuf>,
#[arg(long, value_name = "NAME")]
pub root_dir: Option<String>,
#[arg(long, value_name = "DIR")]
pub bin_dir: Option<String>,
#[arg(long, value_name = "FORMAT")]
pub format: Vec<Format>,
#[arg(long, value_name = "NAME")]
pub user: Option<String>,
#[arg(long, value_name = "NAME")]
pub group: Option<String>,
#[arg(long, value_name = "N", value_parser = clap::value_parser!(u32).range(1..=9))]
pub compression_level: Option<u32>,
#[arg(long, value_name = "EPOCH", env = "SOURCE_DATE_EPOCH")]
pub source_date: Option<u64>,
#[arg(short, long)]
pub verbose: bool,
#[arg(short, long, conflicts_with = "verbose")]
pub quiet: bool,
}
impl TarballArgs {
pub fn from_env() -> Self {
TarballArgs::from_iter(std::env::args_os())
}
fn from_iter(argv: impl IntoIterator<Item = OsString>) -> Self {
let argv: Vec<OsString> = argv.into_iter().collect();
if argv.get(1).is_some_and(|arg| arg == "tar") {
let Cargo::Tarball(args) = Cargo::parse_from(argv);
args
} else {
Parser::parse_from(argv)
}
}
pub fn formats(&self) -> Vec<Format> {
self.format.clone()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn args(argv: &[&str]) -> TarballArgs {
TarballArgs::from_iter(argv.iter().map(OsString::from))
}
#[test]
fn test_parses_both_invocation_forms() {
let direct = args(&["cargo-tar", "--format", "tar"]);
let via_cargo = args(&["cargo-tar", "tar", "--format", "tar"]);
assert_eq!(direct.format, [Format::Tar]);
assert_eq!(via_cargo.format, [Format::Tar]);
}
#[test]
fn test_profile_defaults_to_release() {
assert_eq!(args(&["cargo-tar"]).profile, "release");
assert_eq!(args(&["cargo-tar", "--profile", "release"]).profile, "release");
assert_eq!(args(&["cargo-tar", "--profile", "dev"]).profile, "dev");
assert_eq!(args(&["cargo-tar", "--profile", "fast"]).profile, "fast");
}
}