use lifeloop::host_assets::{HostAdapter, IntegrationMode, render_applied_assets, supports_mode};
use serde::Serialize;
use super::{CliError, print_json};
#[derive(Serialize)]
struct AssetRow<'a> {
relative_path: &'a str,
mode: Option<u32>,
contents: &'a str,
}
pub fn run<I: Iterator<Item = String>>(mut args: I) -> Result<(), CliError> {
let action = args
.next()
.ok_or_else(|| CliError::Usage("asset requires a subcommand: preview".to_string()))?;
match action.as_str() {
"preview" => run_preview(args),
"apply" => Err(CliError::Usage(
"asset: `apply` was removed in lifeloop.v0.2; use `asset preview` (it never wrote to \
the filesystem). See docs/decisions/asset-apply-boundary.md."
.to_string(),
)),
other => Err(CliError::Usage(format!(
"asset: unknown subcommand `{other}` (expected: preview)"
))),
}
}
fn run_preview<I: Iterator<Item = String>>(mut args: I) -> Result<(), CliError> {
let mut host_id: Option<String> = None;
let mut mode_id: Option<String> = None;
while let Some(arg) = args.next() {
match arg.as_str() {
"--host" => {
host_id = Some(require_value(&arg, args.next())?);
}
"--mode" => {
mode_id = Some(require_value(&arg, args.next())?);
}
other => {
return Err(CliError::Usage(format!("asset: unknown flag `{other}`")));
}
}
}
let host_id =
host_id.ok_or_else(|| CliError::Usage("asset: --host <id> is required".into()))?;
let mode_id =
mode_id.ok_or_else(|| CliError::Usage("asset: --mode <mode> is required".into()))?;
let host = HostAdapter::from_id(&host_id)
.ok_or_else(|| CliError::Validation(format!("asset: unknown host `{host_id}`")))?;
let mode = IntegrationMode::from_id(&mode_id)
.ok_or_else(|| CliError::Validation(format!("asset: unknown mode `{mode_id}`")))?;
if !supports_mode(host, mode) {
return Err(CliError::Validation(format!(
"asset: host `{}` does not support mode `{}`",
host.as_str(),
mode.as_str()
)));
}
let assets = render_applied_assets(host, mode);
let rows: Vec<AssetRow<'_>> = assets
.iter()
.map(|a| AssetRow {
relative_path: a.relative_path,
mode: a.mode,
contents: &a.contents,
})
.collect();
print_json(&rows)
}
fn require_value(flag: &str, value: Option<String>) -> Result<String, CliError> {
value.ok_or_else(|| CliError::Usage(format!("flag `{flag}` requires a value")))
}