use std::path::PathBuf;
#[derive(Debug, clap::Args)]
pub struct CapabilitiesArgs {
#[arg(long)]
pub json: bool,
#[arg(long, value_name = "COMPONENT.wasm")]
pub check: Option<PathBuf>,
}
pub fn run(args: CapabilitiesArgs) {
if let Some(component) = args.check.as_ref() {
check_component(component, args.json);
return;
}
let caps: crate::handler_validate::HostCapabilities =
crate::handler_validate::host_capabilities();
if args.json {
println!(
"{}",
serde_json::to_string_pretty(&caps).expect("host capabilities serialize")
);
} else {
println!("package: {}@{}", caps.package, caps.version);
println!("declarable imports: {}", caps.declarable_imports.join(", "));
let feats = caps
.features
.iter()
.map(|c| format!("{} ({})", c.name, c.lifecycle.as_str()))
.collect::<Vec<_>>()
.join(", ");
println!("capability features: {feats}");
}
}
#[cfg(feature = "handlers")]
fn check_component(component: &std::path::Path, json: bool) {
let bytes = match std::fs::read(component) {
Ok(b) => b,
Err(err) => {
eprintln!("cannot read {}: {err}", component.display());
std::process::exit(2);
}
};
let required = boatramp_server::component_requires(&bytes);
let unmet = boatramp_server::unmet_requires(&bytes);
if json {
let report = serde_json::json!({
"component": component.display().to_string(),
"requires": required,
"unmet": unmet,
"ok": unmet.is_empty(),
});
println!(
"{}",
serde_json::to_string_pretty(&report).expect("check report serialize")
);
} else if required.is_empty() {
println!(
"ok: {} declares no capability requirements",
component.display()
);
} else if unmet.is_empty() {
println!(
"ok: this host satisfies all {} requirement(s): {}",
required.len(),
required.join(", ")
);
} else {
eprintln!(
"MISSING: this host does not implement {}: {}",
if unmet.len() == 1 {
"capability"
} else {
"capabilities"
},
unmet.join(", ")
);
eprintln!("required: {}", required.join(", "));
eprintln!("upgrade boatramp or enable those features — see `boatramp capabilities`.");
}
if !unmet.is_empty() {
std::process::exit(1);
}
}
#[cfg(not(feature = "handlers"))]
fn check_component(_component: &std::path::Path, _json: bool) {
eprintln!("`capabilities check` needs a build with the `handlers` feature");
std::process::exit(2);
}