use std::process::ExitCode;
use ::usage::Spec;
use clap::Command;
use crate::formatdoc;
#[must_use]
pub fn spec(mut command: Command, bin: &str) -> String {
command.set_bin_name(bin);
let mut spec = Spec::from(&command);
spec.name = bin.to_string();
spec.bin = bin.to_string();
spec.to_string()
}
#[must_use]
pub fn mount_line(task: &str) -> String {
formatdoc! {r#"#USAGE mount "mise run --quiet {task} -- --usage-spec={task}""#}
}
#[must_use]
pub fn take<C: clap::CommandFactory>(default_bin: &str) -> Option<ExitCode> {
let bin = spec_bin(std::env::args().skip(1), default_bin)?;
print!("{}", spec(C::command(), &bin));
Some(ExitCode::SUCCESS)
}
#[must_use]
pub fn spec_bin(
args: impl IntoIterator<Item = impl AsRef<str>>,
default_bin: &str,
) -> Option<String> {
for arg in args {
let arg = arg.as_ref();
if arg == "--" {
break;
}
if arg == "--usage-spec" {
return Some(default_bin.to_owned());
}
if let Some(bin) = arg.strip_prefix("--usage-spec=") {
return Some(if bin.is_empty() {
default_bin.to_owned()
} else {
bin.to_owned()
});
}
}
None
}
#[cfg(test)]
mod tests {
use clap::{CommandFactory, Parser};
use super::{mount_line, spec, spec_bin};
#[derive(Parser)]
#[command(name = "toy")]
struct Toy {
#[command(subcommand)]
command: ToyCommand,
}
#[derive(clap::Subcommand)]
enum ToyCommand {
Status,
Check,
}
#[test]
fn spec_bin_reads_equals_and_bare() {
assert_eq!(spec_bin(["--usage-spec"], "qctl").as_deref(), Some("qctl"));
assert_eq!(spec_bin(["--usage-spec=q"], "qctl").as_deref(), Some("q"));
assert_eq!(spec_bin(["status"], "qctl"), None);
assert_eq!(spec_bin(["status", "--", "--usage-spec"], "qctl"), None);
assert_eq!(
spec_bin(["--usage-spec=q", "--", "status"], "qctl").as_deref(),
Some("q")
);
}
#[test]
fn spec_names_the_mounted_bin() {
let text = spec(Toy::command(), "q");
assert!(text.contains("name") && text.contains("status"), "{text}");
}
#[test]
fn mount_line_is_the_mise_bootstrap() {
assert_eq!(
mount_line("q"),
r#"#USAGE mount "mise run --quiet q -- --usage-spec=q""#
);
}
}