use cargo_athena::{ContainerRunMeta, serde_json};
use std::process::{Stdio, exit};
use crate::pkg::PkgSel;
#[derive(clap::Args)]
pub struct LsArgs {
#[command(flatten)]
pkg: PkgSel,
}
#[derive(clap::Args)]
pub struct WorkflowLsArgs {
#[command(flatten)]
pkg: PkgSel,
#[arg(long)]
include_synthetic: bool,
}
pub fn container_ls(a: LsArgs) {
let (pkg, bin) = a.pkg.resolve();
let all = fetch_list(pkg.as_deref(), bin.as_deref());
print_table(all.iter().filter(|m| m.kind == "container").collect());
}
pub fn workflow_ls(a: WorkflowLsArgs) {
let (pkg, bin) = a.pkg.resolve();
let all = fetch_list(pkg.as_deref(), bin.as_deref());
print_table(
all.iter()
.filter(|m| a.include_synthetic || !m.synthetic)
.collect(),
);
}
fn fetch_list(pkg: Option<&str>, bin: Option<&str>) -> Vec<ContainerRunMeta> {
let mut cmd = crate::cargo_run(pkg, bin);
cmd.env("CARGO_ATHENA_LIST", "1");
cmd.stderr(Stdio::inherit());
let out = cmd
.output()
.unwrap_or_else(|e| die(&format!("failed to spawn `cargo run`: {e}")));
if !out.status.success() || out.stdout.is_empty() {
die("could not list templates (run from your workflow crate, or pass --package/--bin)");
}
serde_json::from_slice(&out.stdout)
.unwrap_or_else(|e| die(&format!("could not parse template list ({e})")))
}
fn print_table(mut rows: Vec<&ContainerRunMeta>) {
use console::Style;
rows.sort_by(|x, y| x.name.cmp(&y.name));
if rows.is_empty() {
eprintln!("(no matching templates)");
return;
}
let header_s = Style::new().dim().bold();
let pkg_s = Style::new().dim();
let name_s = Style::new().bold();
let kind_container = Style::new().cyan();
let kind_workflow = Style::new().magenta();
let kind_other = Style::new();
let short = |m: &ContainerRunMeta| -> String {
let pfx = format!("{}-", m.package);
m.name.strip_prefix(&pfx).unwrap_or(&m.name).to_string()
};
let sig = |m: &ContainerRunMeta| -> String {
let inner = m
.params
.iter()
.map(|p| {
if p.ty.is_empty() {
p.name.clone()
} else {
format!("{}: {}", p.name, p.ty)
}
})
.collect::<Vec<_>>()
.join(", ");
format!("({inner})")
};
let pw = rows
.iter()
.map(|m| m.package.len())
.max()
.unwrap_or(7)
.max(7);
let nw = rows
.iter()
.map(|m| short(m).len())
.max()
.unwrap_or(4)
.max(4);
println!(
"{} {} {} {}",
header_s.apply_to(format!("{:<pw$}", "PACKAGE", pw = pw)),
header_s.apply_to(format!("{:<nw$}", "NAME", nw = nw)),
header_s.apply_to("KIND "),
header_s.apply_to("SIGNATURE"),
);
for m in rows {
let kind_s = match m.kind.as_str() {
"container" => &kind_container,
"workflow" => &kind_workflow,
_ => &kind_other,
};
println!(
"{} {} {} {}",
pkg_s.apply_to(format!("{:<pw$}", m.package, pw = pw)),
name_s.apply_to(format!("{:<nw$}", short(m), nw = nw)),
kind_s.apply_to(format!("{:<9}", m.kind)),
sig(m),
);
}
}
fn die(msg: &str) -> ! {
eprintln!("cargo athena ls: {msg}");
exit(2);
}